Skip to content

Commit

Permalink
Merge pull request #150 from swaggerexpert/next
Browse files Browse the repository at this point in the history
Align with official OpenAPI ABNF
  • Loading branch information
char0n authored Dec 22, 2024
2 parents adce587 + d5a577b commit 6b4f27e
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 346 deletions.
6 changes: 6 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ openapi-path-templating
Copyright 2023, Vladimír Gorej
openapi-path-templating is licensed under Apache 2.0 license.
Copy of the Apache 2.0 license can be found in `LICENSE` file.

OpenAPI Specification 3.1.x
Copyright The Linux Foundation
Fragments of the specification text are embedded in `README.md`.
Definition of `template-expression-param-name` ABNF non-terminal is based on the OpenAPI Specification ABNF.
Copy of the Apache 2.0 license can be found in `LICENSE` file.
77 changes: 33 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
[![try on RunKit](https://img.shields.io/badge/try%20on-RunKit-brightgreen.svg?style=flat)](https://npm.runkit.com/openapi-path-templating)
[![Tidelift](https://tidelift.com/badges/package/npm/openapi-path-templating)](https://tidelift.com/subscription/pkg/npm-openapi-path-templating?utm_source=npm-openapi-path-templating&utm_medium=referral&utm_campaign=readme)

[Path Templating](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathTemplating) allow defining values based on information that will only be available within the HTTP message in an actual API call.
This mechanism is used by [Paths Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#paths-object)
of [OpenAPI specification](https://github.com/OAI/OpenAPI-Specification).
[OpenAPI Path Templating](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#path-templating) refers to the usage of template expressions, delimited by curly braces (`{}`), to mark a section of a URL path as replaceable using path parameters.
Each template expression in the path MUST correspond to a path parameter that is included in the [Path Item](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#path-item-object) itself and/or in each of the Path Item's [Operations](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#operation-object).
An exception is if the path item is empty, for example due to ACL constraints, matching path parameters are not required.

`openapi-path-templating` is a **parser**, **validator** and **resolver** for OpenAPI Path Templating. It supports
Path Templating defined in following OpenAPI specification versions:
`openapi-path-templating` is a **parser**, **validator**, and **resolver** for OpenAPI Path Templating,
which played a [foundational role](https://github.com/OAI/OpenAPI-Specification/pull/4244) in defining the official ANBF grammar for OpenAPI Path Templating.

It supports Path Templating defined in following OpenAPI specification versions:

- [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#pathTemplating)
- [OpenAPI 3.0.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#pathTemplating)
Expand Down Expand Up @@ -63,7 +65,7 @@ You can install `openapi-path-templating` using `npm`:
### Usage

`openapi-path-templating` currently supports **parsing**, **validation** and **resolution**.
Both 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))
Both parser and validator are based on a superset of [ABNF](https://www.rfc-editor.org/rfc/rfc5234) ([SABNF](https://github.com/ldthomas/apg-js2/blob/master/SABNF.md))
and use [apg-lite](https://github.com/ldthomas/apg-lite) parser generator.

#### Parsing
Expand All @@ -89,17 +91,12 @@ parseResult.result.success; // => true
length: 13,
matched: 13,
maxMatched: 13,
maxTreeDepth: 18,
nodeHits: 324
maxTreeDepth: 20,
nodeHits: 232
},
ast: fnast {
callbacks: [
'path-template': [Function: pathTemplate],
path: [Function: path],
query: [Function: query],
'query-marker': [Function: queryMarker],
fragment: [Function: fragment],
'fragment-marker': [Function: fragmentMarker],
slash: [Function: slash],
'path-literal': [Function: pathLiteral],
'template-expression': [Function: templateExpression],
Expand Down Expand Up @@ -134,7 +131,6 @@ After running the above code, **parts** variable has the following shape:
```js
[
[ 'path-template', '/pets/{petId}' ],
[ 'path', '/pets/{petId}' ],
[ 'slash', '/' ],
[ 'path-literal', 'pets' ],
[ 'slash', '/' ],
Expand All @@ -156,29 +152,26 @@ After running the above code, **xml** variable has the following content:

```xml
<?xml version="1.0" encoding="utf-8"?>
<root nodes="7" characters="13">
<root nodes="6" characters="13">
<!-- input string -->
/pets/{petId}
<node name="path-template" index="0" length="13">
/pets/{petId}
<node name="path" index="0" length="13">
/pets/{petId}
<node name="slash" index="0" length="1">
/
</node><!-- name="slash" -->
<node name="path-literal" index="1" length="4">
pets
</node><!-- name="path-literal" -->
<node name="slash" index="5" length="1">
/
</node><!-- name="slash" -->
<node name="template-expression" index="6" length="7">
{petId}
<node name="template-expression-param-name" index="7" length="5">
petId
</node><!-- name="template-expression-param-name" -->
</node><!-- name="template-expression" -->
</node><!-- name="path" -->
<node name="slash" index="0" length="1">
/
</node><!-- name="slash" -->
<node name="path-literal" index="1" length="4">
pets
</node><!-- name="path-literal" -->
<node name="slash" index="5" length="1">
/
</node><!-- name="slash" -->
<node name="template-expression" index="6" length="7">
{petId}
<node name="template-expression-param-name" index="7" length="5">
petId
</node><!-- name="template-expression-param-name" -->
</node><!-- name="template-expression" -->
</node><!-- name="path-template" -->
</root>
```
Expand Down Expand Up @@ -248,21 +241,17 @@ The Path Templating is defined by the following [ABNF](https://tools.ietf.org/ht

```abnf
; OpenAPI Path Templating ABNF syntax
path-template = path [ query-marker query ] [ fragment-marker fragment ]
path = slash *( path-segment slash ) [ path-segment ]
path-segment = 1*( path-literal / template-expression )
query = *( query-literal )
query-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" / "&" / "=" )
query-marker = "?"
fragment = *( fragment-literal )
fragment-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" )
fragment-marker = "#"
; Aligned with RFC 3986 (https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
path-template = slash [ path-template-nz ]
path-template-nz = path-segment *( slash path-segment )
slash = "/"
path-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
path-segment = 1*( path-literal / template-expression )
path-literal = 1*pchar
template-expression = "{" template-expression-param-name "}"
template-expression-param-name = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
template-expression-param-name = 1*pchar
; Characters definitions (from RFC 3986)
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded = "%" HEXDIG HEXDIG
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
Expand Down
12 changes: 0 additions & 12 deletions src/parse/callbacks/fragment-marker.js

This file was deleted.

12 changes: 0 additions & 12 deletions src/parse/callbacks/fragment.js

This file was deleted.

12 changes: 0 additions & 12 deletions src/parse/callbacks/path.js

This file was deleted.

12 changes: 0 additions & 12 deletions src/parse/callbacks/query-marker.js

This file was deleted.

12 changes: 0 additions & 12 deletions src/parse/callbacks/query.js

This file was deleted.

10 changes: 0 additions & 10 deletions src/parse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@ import { Ast as AST, Parser } from 'apg-lite';
import Grammar from '../path-templating.js';
import slashCallback from './callbacks/slash.js';
import pathTemplateCallback from './callbacks/path-template.js';
import pathCallback from './callbacks/path.js';
import pathLiteralCallback from './callbacks/path-literal.js';
import queryCallback from './callbacks/query.js';
import queryMarkerCallback from './callbacks/query-marker.js';
import fragmentCallback from './callbacks/fragment.js';
import fragmentMarkerCallback from './callbacks/fragment-marker.js';
import templateExpressionCallback from './callbacks/template-expression.js';
import templateExpressionParamNameCallback from './callbacks/template-expression-param-name.js';

Expand All @@ -19,11 +14,6 @@ const parse = (pathTemplate) => {

parser.ast = new AST();
parser.ast.callbacks['path-template'] = pathTemplateCallback;
parser.ast.callbacks['path'] = pathCallback;
parser.ast.callbacks['query'] = queryCallback;
parser.ast.callbacks['query-marker'] = queryMarkerCallback;
parser.ast.callbacks['fragment'] = fragmentCallback;
parser.ast.callbacks['fragment-marker'] = fragmentMarkerCallback;
parser.ast.callbacks['slash'] = slashCallback;
parser.ast.callbacks['path-literal'] = pathLiteralCallback;
parser.ast.callbacks['template-expression'] = templateExpressionCallback;
Expand Down
16 changes: 6 additions & 10 deletions src/path-templating.bnf
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
; OpenAPI Path Templating ABNF syntax
path-template = path [ query-marker query ] [ fragment-marker fragment ]
path = slash *( path-segment slash ) [ path-segment ]
path-template = slash *( path-segment slash ) [ path-segment ]
path-segment = 1*( path-literal / template-expression )
query = *( query-literal )
query-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" / "&" / "=" )
query-marker = "?"
fragment = *( fragment-literal )
fragment-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" )
fragment-marker = "#"
slash = "/"
path-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
path-literal = 1*pchar
template-expression = "{" template-expression-param-name "}"
template-expression-param-name = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
template-expression-param-name = 1*( %x00-79 / %x7C / %x7E-10FFFF ) ; every UTF8 character except { and } (from OpenAPI)

; Characters definitions (from RFC 3986)
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
pct-encoded = "%" HEXDIG HEXDIG
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="

; Characters definitions (from RFC 5234)
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
DIGIT = %x30-39 ; 0-9
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
Loading

0 comments on commit 6b4f27e

Please sign in to comment.