{"id":23906816,"url":"https://github.com/swaggerexpert/openapi-runtime-expression","last_synced_at":"2025-04-11T04:36:43.017Z","repository":{"id":62326303,"uuid":"558798413","full_name":"swaggerexpert/openapi-runtime-expression","owner":"swaggerexpert","description":"OpenAPI Runtime Expressions parser, validator and extractor.","archived":false,"fork":false,"pushed_at":"2025-03-24T21:27:48.000Z","size":538,"stargazers_count":7,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-11T04:36:34.398Z","etag":null,"topics":["expression","extractor","openapi3","openapi31","parser","runtime","validator"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swaggerexpert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":"GOVERNANCE.md","roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["char0n"],"patreon":"char0n","ko_fi":"char0n","liberapay":"char0n","issuehunt":"char0n"}},"created_at":"2022-10-28T10:18:43.000Z","updated_at":"2025-03-24T21:27:52.000Z","dependencies_parsed_at":"2024-03-26T21:28:17.515Z","dependency_job_id":"c31e7c70-f5ba-42aa-99d1-784fc4b5083b","html_url":"https://github.com/swaggerexpert/openapi-runtime-expression","commit_stats":{"total_commits":131,"total_committers":3,"mean_commits":"43.666666666666664","dds":0.3129770992366412,"last_synced_commit":"d55ca8d83ec97547a903a5c5c04b0671b5bc5647"},"previous_names":["swaggerexpert/openapi-runtime-expression"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fopenapi-runtime-expression","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fopenapi-runtime-expression/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fopenapi-runtime-expression/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swaggerexpert%2Fopenapi-runtime-expression/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swaggerexpert","download_url":"https://codeload.github.com/swaggerexpert/openapi-runtime-expression/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345257,"owners_count":21088231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["expression","extractor","openapi3","openapi31","parser","runtime","validator"],"created_at":"2025-01-05T02:14:48.696Z","updated_at":"2025-04-11T04:36:43.005Z","avatar_url":"https://github.com/swaggerexpert.png","language":"JavaScript","readme":"# @swaggerexpert/openapi-runtime-expression\n\n[![npmversion](https://img.shields.io/npm/v/%40swaggerexpert%2Fopenapi-runtime-expression?style=flat-square\u0026label=npm%20package\u0026color=%234DC81F\u0026link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40swaggerexpert%2Fopenapi-runtime-expression)](https://www.npmjs.com/package/@swaggerexpert/openapi-runtime-expression)\n[![npm](https://img.shields.io/npm/dm/@swaggerexpert/openapi-runtime-expression)](https://www.npmjs.com/package/@swaggerexpert/openapi-runtime-expression)\n[![Test workflow](https://github.com/swaggerexpert/openapi-runtime-expression/actions/workflows/test.yml/badge.svg)](https://github.com/swaggerexpert/openapi-runtime-expression/actions)\n[![Dependabot enabled](https://img.shields.io/badge/Dependabot-enabled-blue.svg)](https://dependabot.com/)\n[![try on RunKit](https://img.shields.io/badge/try%20on-RunKit-brightgreen.svg?style=flat)](https://npm.runkit.com/@swaggerexpert/openapi-runtime-expression)\n[![Tidelift](https://tidelift.com/badges/package/npm/@swaggerexpert%2Fopenapi-runtime-expression)](https://tidelift.com/subscription/pkg/npm-.swaggerexpert-openapi-runtime-expression?utm_source=npm-swaggerexpert-openapi-runtime-expression\u0026utm_medium=referral\u0026utm_campaign=readme)\n\n[OpenAPI Runtime Expressions](https://spec.openapis.org/oas/v3.1.1.html#runtime-expressions) allow defining values based on information that will only be available within the HTTP message in an actual API call.\nThis mechanism is used by [Link Objects](https://spec.openapis.org/oas/v3.1.1.html#link-object) and [Callback Objects](https://spec.openapis.org/oas/v3.1.1.html#callback-object)\nof [OpenAPI specification](https://spec.openapis.org/#openapi-specification).\n\n`@swaggerexpert/openapi-runtime-expression` is a **parser**, **validator** and **extractor** for OpenAPI Runtime Expressions.\n\nIt supports Runtime Expressions defined in following OpenAPI specification versions:\n\n- [OpenAPI 3.0.0](https://spec.openapis.org/oas/v3.0.0.html#runtime-expressions)\n- [OpenAPI 3.0.1](https://spec.openapis.org/oas/v3.0.1.html#runtime-expressions)\n- [OpenAPI 3.0.2](https://spec.openapis.org/oas/v3.0.2.html#runtime-expressions)\n- [OpenAPI 3.0.3](https://spec.openapis.org/oas/v3.0.3.html#runtime-expressions)\n- [OpenAPI 3.0.4](https://spec.openapis.org/oas/v3.0.4.html#runtime-expressions)\n- [OpenAPI 3.1.0](https://spec.openapis.org/oas/v3.1.0.html#runtime-expressions)\n- [OpenAPI 3.1.1](https://spec.openapis.org/oas/v3.1.1.html#runtime-expressions)\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"right\" valign=\"middle\"\u003e\n        \u003cimg src=\"https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png\" alt=\"Tidelift\" width=\"60\" /\u003e\n      \u003c/td\u003e\n      \u003ctd valign=\"middle\"\u003e\n        \u003ca href=\"https://tidelift.com/subscription/pkg/npm-.swaggerexpert-openapi-runtime-expression?utm_source=npm-swaggerexpert-openapi-runtime-expression\u0026utm_medium=referral\u0026utm_campaign=readme\"\u003e\n            Get professionally supported @swaggerexpert/openapi-runtime-expression with Tidelift Subscription.\n        \u003c/a\u003e\n      \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Table of Contents\n\n- [Getting started](#getting-started)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Extraction](#extraction)\n    - [Parsing](#parsing)\n    - [Validation](#validation)\n    - [Grammar](#grammar)\n- [More about OpenAPI runtime expressions](#more-about-openapi-runtime-expressions)\n- [License](#license)\n\n\n## Getting started\n\n### Installation\n\nYou can install `@swaggerexpert/openapi-runtime-expression` using `npm`:\n\n```sh\n $ npm install @swaggerexpert/openapi-runtime-expression\n```\n\n### Usage\n\n`@swaggerexpert/openapi-runtime-expression` currently supports **extraction**, **parsing** and **validation**.\nBoth parser and validator are based on a superset of [ABNF](https://www.rfc-editor.org/rfc/rfc5234) ([SABNF](https://cs.github.com/ldthomas/apg-js2/blob/master/SABNF.md))\nand use [apg-lite](https://github.com/ldthomas/apg-lite) parser generator.\n\n#### Extraction\n\nOpenAPI embeds Runtime Expressions into string values surrounded with `{}` curly braces.\nTo extract Runtime Expressions from this embedded form, use the **extract** function.\nExtracted Runtime Expression can be used for further parsing of validation.\n\n```js\nimport { extract, test, parse } from '@swaggerexpert/openapi-runtime-expression';\n\nconst expression = extract('{$request.header.accept}'); // =\u003e '$request.header.accept'\n\ntest(expression); // =\u003e true\nparse(expression); // =\u003e { result, ast }\n```\n\n#### Parsing\n\nParsing a Runtime Expression is as simple as importing the **parse** function and calling it.\n\n```js\nimport { parse } from '@swaggerexpert/openapi-runtime-expression';\n\nconst parseResult = parse('$request.header.accept');\n```\n\n`token` non-terminal is by default being normalized to lower case.\n\n```js\nimport { parse } from '@swaggerexpert/openapi-runtime-expression';\n\nconst parseResult = parse('$request.header.Accept');\nconst parts = [];\n\nparseResult.ast.translate(parts);\n// [\n//   [ 'expression', '$request.header.Accept' ],\n//   [ 'source', 'header.Accept' ],\n//   [ 'header-reference', 'header.Accept' ],\n//   [ 'token', 'accept' ],\n// ]\n```\n\n`token` normalization can be overridden by passing token normalizer to the `parse` function.\n\n**Upper case**\n\n```js\nimport { parse, tokenUpperCaseNormalizer } from '@swaggerexpert/openapi-runtime-expression';\n\nconst parseResult = parse('$request.header.Accept', { tokenNormalizer: tokenUpperCaseNormalizer });\nconst parts = [];\nparseResult.ast.translate(parts);\n// [\n//   [ 'expression', '$request.header.Accept' ],\n//   [ 'source', 'header.Accept' ],\n//   [ 'header-reference', 'header.Accept' ],\n//   [ 'token', 'ACCEPT' ],\n// ]`\n```\n\n**Lower case**\n\n```js\nimport { parse, tokenLowerCaseNormalizer } from '@swaggerexpert/openapi-runtime-expression';\n\nconst parseResult = parse('$request.header.Accept', { tokenNormalizer: tokenLowerCaseNormalizer });\nconst parts = [];\nparseResult.ast.translate(parts);\n// [\n//   [ 'expression', '$request.header.Accept' ],\n//   [ 'source', 'header.Accept' ],\n//   [ 'header-reference', 'header.Accept' ],\n//   [ 'token', 'accept' ],\n// ]`\n```\n\n**parseResult** variable has the following shape:\n\n```\n{\n  result: {\n    success: true,\n    state: 101,\n    stateName: 'MATCH',\n    length: 22,\n    matched: 22,\n    maxMatched: 22,\n    maxTreeDepth: 13,\n    nodeHits: 152\n  },\n  ast: fnast {\n    callbacks: [\n      expression: [Function: expression],\n      source: [Function: source],\n      'header-reference': [Function: headerReference],\n      'query-reference': [Function: queryReference],\n      'path-reference': [Function: pathReference],\n      'body-reference': [Function: bodyReference],\n      'json-pointer': [Function: jsonPointer],\n      'reference-token': [Function: referenceToken],\n      name: [Function: name],\n      token: [Function: token]\n    ],\n    init: [Function (anonymous)],\n    ruleDefined: [Function (anonymous)],\n    udtDefined: [Function (anonymous)],\n    down: [Function (anonymous)],\n    up: [Function (anonymous)],\n    translate: [Function (anonymous)],\n    setLength: [Function (anonymous)],\n    getLength: [Function (anonymous)],\n    toXml: [Function (anonymous)]\n  }\n}\n```\n\n###### Interpreting AST as list of entries\n\n```js\nimport { parse } from '@swaggerexpert/openapi-runtime-expression';\n\nconst parseResult = parse('$request.header.accept');\nconst parts = [];\n\nparseResult.ast.translate(parts);\n```\n\nAfter running the above code, **parts** variable has the following shape:\n\n```js\n[\n  [ 'expression', '$request.header.accept' ],\n  [ 'source', 'header.accept' ],\n  [ 'header-reference', 'header.accept' ],\n  [ 'token', 'accept' ],\n]\n```\n\n###### Interpreting AST as XML\n\n```js\nimport { parse } from '@swaggerexpert/openapi-runtime-expression';\n\nconst parseResult = parse('$request.header.accept');\nconst xml = parseResult.ast.toXml();\n```\n\nAfter running the above code, **xml** variable has the following content:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003croot nodes=\"4\" characters=\"22\"\u003e\n  \u003c!-- input string --\u003e\n  $request.header.accept\n  \u003cnode name=\"expression\" index=\"0\" length=\"22\"\u003e\n    $request.header.accept\n    \u003cnode name=\"source\" index=\"9\" length=\"13\"\u003e\n      header.accept\n      \u003cnode name=\"header-reference\" index=\"9\" length=\"13\"\u003e\n        header.accept\n        \u003cnode name=\"token\" index=\"16\" length=\"6\"\u003e\n          accept\n        \u003c/node\u003e\u003c!-- name=\"token\" --\u003e\n      \u003c/node\u003e\u003c!-- name=\"header-reference\" --\u003e\n    \u003c/node\u003e\u003c!-- name=\"source\" --\u003e\n  \u003c/node\u003e\u003c!-- name=\"expression\" --\u003e\n\u003c/root\u003e\n```\n\n\u003e NOTE: AST can also be traversed in classical way using [depth first traversal](https://www.tutorialspoint.com/data_structures_algorithms/depth_first_traversal.htm). For more information about this option please refer to [apg-js](https://github.com/ldthomas/apg-js) and [apg-js-examples](https://github.com/ldthomas/apg-js-examples).\n\n#### Validation\n\nValidating a Runtime Expression is as simple as importing the **test** function and calling it.\n\n```js\nimport { test } from '@swaggerexpert/openapi-runtime-expression';\n\ntest('$request.header.accept'); // =\u003e true\ntest('nonsensical string'); // =\u003e false\n```\n\n#### Grammar\n\nNew grammar instance can be created in following way:\n\n```js\nimport { Grammar } from '@swaggerexpert/openapi-runtime-expression';\n\nconst grammar = new Grammar();\n```\n\nTo obtain original ABNF (SABNF) grammar as a string:\n\n```js\nimport { Grammar } from '@swaggerexpert/openapi-runtime-expression';\n\nconst grammar = new Grammar();\n\ngrammar.toString();\n// or\nString(grammar);\n```\n\n## More about OpenAPI runtime expressions\n\nThe runtime expression is defined by the following [ABNF](https://tools.ietf.org/html/rfc5234) syntax\n\n```abnf\n; OpenAPI runtime expression ABNF syntax\nexpression       = \"$url\" / \"$method\" / \"$statusCode\" / \"$request.\" source / \"$response.\" source\nsource           = header-reference / query-reference / path-reference / body-reference\nheader-reference = \"header.\" token\nquery-reference  = \"query.\" name\npath-reference   = \"path.\" name\nbody-reference   = \"body\" [\"#\" json-pointer ]\nname             = *( CHAR )\n\n; https://datatracker.ietf.org/doc/html/rfc6901#section-3\njson-pointer     = *( \"/\" reference-token )\nreference-token  = *( unescaped / escaped )\nunescaped        = %x00-2E / %x30-7D / %x7F-10FFFF\n                 ; %x2F ('/') and %x7E ('~') are excluded from 'unescaped'\nescaped          = \"~\" ( \"0\" / \"1\" )\n                 ; representing '~' and '/', respectively\n\n; https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6\ntoken          = 1*tchar\ntchar          = \"!\" / \"#\" / \"$\" / \"%\" / \"\u0026\" / \"'\" / \"*\"\n               / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n               / DIGIT / ALPHA\n               ; any VCHAR, except delimiters\n\n; https://www.rfc-editor.org/rfc/rfc7159#section-7\nCHAR = unescape /\n    escape (\n        %x22 /          ; \"    quotation mark  U+0022\n        %x5C /          ; \\    reverse solidus U+005C\n        %x2F /          ; /    solidus         U+002F\n        %x62 /          ; b    backspace       U+0008\n        %x66 /          ; f    form feed       U+000C\n        %x6E /          ; n    line feed       U+000A\n        %x72 /          ; r    carriage return U+000D\n        %x74 /          ; t    tab             U+0009\n        %x75 4HEXDIG )  ; uXXXX                U+XXXX\nescape         = %x5C   ; \\\nunescape       = %x20-21 / %x23-5B / %x5D-10FFFF\n\n; https://datatracker.ietf.org/doc/html/rfc5234#appendix-B.1\nHEXDIG         =  DIGIT / \"A\" / \"B\" / \"C\" / \"D\" / \"E\" / \"F\"\nDIGIT          =  %x30-39   ; 0-9\nALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z\n```\n\nThe `name` identifier is case-sensitive, whereas `token` is not.\n\nThe table below provides examples of runtime expressions and examples of their use in a value:\n\n##### Examples\n\n| Source Location | example expression | notes |\n| ---- | :---- | :---- |\n| HTTP Method | `$method` | The allowable values for the `$method` will be those for the HTTP operation. |\n| Requested media type | `$request.header.accept` | |\n| Request parameter | `$request.path.id` | Request parameters MUST be declared in the `parameters` section of the parent operation or they cannot be evaluated. This includes request headers. |\n| Request body property | `$request.body#/user/uuid` | In operations which accept payloads, references may be made to portions of the `requestBody` or the entire body. |\n| Request URL | `$url` | |\n| Response value | `$response.body#/status` | In operations which return payloads, references may be made to portions of the response body or the entire body. |\n| Response header | `$response.header.Server` | Single header values only are available |\n\nRuntime expressions preserve the type of the referenced value.\nExpressions can be embedded into string values by surrounding the expression with `{}` curly braces.\n\n## License\n\n`@swaggerexpert/openapi-runtime-expression` is licensed under [Apache 2.0 license](https://github.com/swaggerexpert/openapi-runtime-expression/blob/main/LICENSE).\n`@swaggerexpert/openapi-runtime-expression` comes with an explicit [NOTICE](https://github.com/swaggerexpert/openapi-runtime-expression/blob/main/NOTICE) file\ncontaining additional legal notices and information.\n","funding_links":["https://github.com/sponsors/char0n","https://patreon.com/char0n","https://ko-fi.com/char0n","https://liberapay.com/char0n","https://issuehunt.io/r/char0n","https://tidelift.com/badges/package/npm/@swaggerexpert%2Fopenapi-runtime-expression","https://tidelift.com/subscription/pkg/npm-.swaggerexpert-openapi-runtime-expression?utm_source=npm-swaggerexpert-openapi-runtime-expression\u0026utm_medium=referral\u0026utm_campaign=readme"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswaggerexpert%2Fopenapi-runtime-expression","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswaggerexpert%2Fopenapi-runtime-expression","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswaggerexpert%2Fopenapi-runtime-expression/lists"}