# Ends With Checks if a string value ends with a specified suffix. ## Overview The `ends_with` condition evaluates whether a field's string value ends with a specified suffix. This is useful for matching file extensions, domain suffixes, ID patterns, and other cases where the ending of a string is significant. ## Use Cases - **File Type Routing**: Route based on file extensions (.json, .csv, .log) - **Domain Matching**: Match email domains or URL suffixes - **ID Pattern Matching**: Route based on ID suffixes or version numbers - **Path-Based Routing**: Match URL paths or file paths by suffix ## Configuration | Setting | Type | Required | Description | | ------------------ | ------- | -------- | -------------------------------------------------------------------------------------------- | | `key` | string | Yes | The field path to check. Supports dot notation for nested fields. Use `*` to check all keys.| | `value` | string | Yes | The suffix to check for. | | `case_insensitive` | boolean | No | If `true`, performs case-insensitive comparison. | | `not` | boolean | No | If `true`, inverts the condition (matches if value does NOT end with suffix). | ## Examples ### File Extension Check Route based on file extension: ```json { "type_id": "ends_with", "config": { "key": "filename", "value": ".json" } } ``` **Matches:** ```json {"filename": "config.json"} {"filename": "data/users.json"} {"filename": ".json"} ``` **Does not match:** ```json {"filename": "config.yaml"} {"filename": "json_file.txt"} {"filename": "config.json.bak"} ``` ### Email Domain Check Match emails from specific domains: ```json { "type_id": "ends_with", "config": { "key": "email", "value": "@company.com", "case_insensitive": true } } ``` **Matches:** ```json {"email": "user@company.com"} {"email": "admin@COMPANY.COM"} {"email": "support@Company.Com"} ``` ### URL Path Matching Route API requests by path suffix: ```json { "type_id": "ends_with", "config": { "key": "path", "value": "/health" } } ``` **Matches:** ```json {"path": "/api/v1/health"} {"path": "/health"} {"path": "/service/health"} ``` ### Version Suffix Check Match version strings: ```json { "type_id": "ends_with", "config": { "key": "version", "value": "-beta" } } ``` **Matches:** ```json {"version": "1.0.0-beta"} {"version": "2.3.1-beta"} ``` **Does not match:** ```json {"version": "1.0.0"} {"version": "1.0.0-rc1"} ``` ### Exclusion Check Match files that are NOT backups: ```json { "type_id": "ends_with", "config": { "key": "filename", "value": ".bak", "not": true } } ``` **Matches:** ```json {"filename": "config.json"} {"filename": "data.csv"} ``` **Does not match:** ```json {"filename": "config.json.bak"} {"filename": "old_data.bak"} ``` ### Nested Field Check Check suffix in nested fields: ```json { "type_id": "ends_with", "config": { "key": "request.url", "value": ".html" } } ``` **Matches:** ```json {"request": {"url": "/pages/about.html"}} {"request": {"url": "/index.html"}} ``` ## Common Patterns ### Route by File Type Separate different file types: ```json { "operator": "or", "conditions": [ {"type_id": "ends_with", "config": {"key": "filename", "value": ".json"}}, {"type_id": "ends_with", "config": {"key": "filename", "value": ".yaml"}}, {"type_id": "ends_with", "config": {"key": "filename", "value": ".yml"}} ] } ``` ### Internal vs External Emails Route based on email domain: ```json { "operator": "and", "conditions": [ {"type_id": "key_exists", "config": {"key": "sender_email"}}, { "type_id": "ends_with", "config": { "key": "sender_email", "value": "@internal.company.com", "case_insensitive": true } } ] } ``` ### API Endpoint Routing Route different API endpoints: ```json { "operator": "or", "conditions": [ {"type_id": "ends_with", "config": {"key": "path", "value": "/create"}}, {"type_id": "ends_with", "config": {"key": "path", "value": "/update"}}, {"type_id": "ends_with", "config": {"key": "path", "value": "/delete"}} ] } ``` ### Exclude Temporary Files Filter out temporary and backup files: ```json { "operator": "and", "conditions": [ {"type_id": "ends_with", "config": {"key": "filename", "value": ".tmp", "not": true}}, {"type_id": "ends_with", "config": {"key": "filename", "value": ".bak", "not": true}}, {"type_id": "ends_with", "config": {"key": "filename", "value": "~", "not": true}} ] } ``` ## Best Practices 1. **Include delimiters**: When matching extensions, include the dot (`.json` not `json`) to avoid false matches. 2. **Use `case_insensitive` for file extensions**: File systems may have mixed case extensions. 3. **Combine with `starts_with`**: For matching both prefix and suffix patterns. 4. **Consider URL encoding**: URL paths may have encoded characters. 5. **Handle trailing characters**: Watch for trailing slashes, spaces, or newlines in data. ## Type Handling - **Strings**: Direct suffix comparison - **Numbers**: Converted to strings first (e.g., `123` ends with `"3"`) - **Booleans**: Converted to "true" or "false" strings - **Arrays/Objects**: Not supported for direct comparison - **Missing fields**: Returns `false` (or `true` if `not` is set) ## Limitations - Simple suffix matching only (no patterns or wildcards) - Single suffix per condition (use `or` for multiple suffixes) - No support for matching multiple suffixes in one condition ## Troubleshooting **Not matching expected values:** - Check for trailing whitespace or special characters - Verify case sensitivity settings - Ensure the full suffix is specified (e.g., `.json` not `json`) **Unexpected matches:** - The suffix might be shorter than intended - Check for similar suffixes (`.js` matches both `.js` and `.mjs` files) **Case sensitivity issues:** - Enable `case_insensitive` for user-generated content - File extensions may vary in case across systems