Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

General Structure

Love it or hate it, ngen uses TOML as its configuration language. ngen requires a reference to a singular, well-formed configuration file to run.

This chapter goes in-depth about what this config file looks like, explaining what makes a config file “well-formed” and what to avoid.

ngen does not assume a particular ordering of configuration file sections.

version = 1

The “header” section of an ngen file is currently very simple, requiring a field version, which holds an integer value from 0 to 255 (inclusive).

This field currently does not serve any purpose other than future proofing. Its intended purpose is to be able to facilitate programmatic distinction between configuration file versions, should this be needed in the future.

general

Every ngen configuration file must contain a section [general], formatted as such:

[general]
# May be empty; array of conversion rules
convert = []
# Boolean value; whether the rules in the `convert` array are
# being considered when generating type mappings
enabled = true
# String, valid path; Where the auto-generated code should be placed.
output = "./example/src/auto_gen/matrix_v113.rs"

Fallback Behavior

Read the chapter “Priority Resolution” in “Route Matching” to learn more.

output

The path in the output directory must be readable and writable by the operating system user executing ngen. Both absolute and relative paths are allowed. The file that is being pointed to in the path will be replaced entirely with the auto-generated code generated by ngen.

For more information on what happens to this file and parent mod.rs files, see the “Generating Code” chapter.

Custom Rulesets

In addition to the general ruleset, an unlimited amount of custom rulesets may be present in the configuration file. Custom rulesets allow you to apply different conversion rules to specific groups of API routes based on regex pattern matching.

Custom rulesets are formatted as such:

[admin_api]         # String, unique per config file; Name of custom ruleset
include_routes = [] # Array of String; Regex patterns of route paths to include in this ruleset
exclude_routes = [] # Array of String; Regex patterns of route paths to exclude from this ruleset
convert = []        # Array of Object; Conversion rules to apply to all matched routes

Route Matching

Custom rulesets use regex patterns to determine which OpenAPI routes they should apply to:

  • include_routes: Array of regex patterns. If any pattern matches a route path, that route is included in this ruleset (unless explicitly excluded).
  • exclude_routes: Array of regex patterns. If any pattern matches a route path, that route is excluded from this ruleset, even if it matches an include pattern.

Exclude patterns take precedence over include patterns.

Example

[matrix_client_v1]
include_routes = ['^/_matrix/client/v1/.*$']  # Include all Matrix client v1 routes
exclude_routes = ['^/_matrix/client/v1/admin/.*$']  # But exclude admin routes
convert = [
    { from = "roomId", to = "RoomId" },
    { from = "userId", to = "UserId" }
]

[admin_api]
include_routes = [
    '^/admin/.*$',                              # All admin routes
    'specific/route/\{id\}/actions'             # Plus this specific route
]
exclude_routes = ['^/admin/health$']            # Except health check
convert = [
    { from = "adminId", to = "AdminUserId" }
]

Priority and Fallback Behavior

Rulesets have priority based on their specificity and definition order:

  1. Custom rulesets are processed first, in the order they appear in the configuration file
  2. General ruleset acts as a fallback for routes not matched by any custom ruleset
  3. Rule inheritance: If the general ruleset is enabled, its rules are merged into custom rulesets, but custom ruleset rules take precedence

Priority Example

[general]
convert = [
    { from = "userId", to = "String" },      # Fallback mapping
    { from = "roomId", to = "String" }       # Fallback mapping
]
enabled = true

[matrix_client_v1]
include_routes = ['^/_matrix/client/v1/.*$']
convert = [
    { from = "roomId", to = "RoomId" }       # Overrides general ruleset for roomId
    # userId inherits from general ruleset (maps to "String")
]

Best Practices

  1. Order matters: Define more specific rulesets before general ones
  2. Use descriptive names: Ruleset names should clearly indicate their purpose
  3. Test regex patterns: Ensure your include/exclude patterns match the intended routes. You can use https://regex101.com/ to help with this. Don’t forget to set the regex engine flavor to “Rust”!