Skip to content

OpenAPI Server URL templating parser, validator and substitution mechanism.

License

Notifications You must be signed in to change notification settings

swaggerexpert/openapi-server-url-templating

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

70 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

openapi-server-url-templating

npmversion npm Test workflow Dependabot enabled try on RunKit Tidelift

Server URL Templating supports Server Variables. Variable substitutions will be made when a variable is named in {brackets}.

This mechanism is used by Server Object of OpenAPI specification.

openapi-server-url-templating is a parser, validator and substitution mechanism for OpenAPI Server URL Templating. It supports Server Object URL Templating defined in following OpenAPI specification versions:

Tidelift Get professionally supported openapi-server-url-templating with Tidelift Subscription.

Table of Contents

Getting started

Installation

You can install openapi-server-url-templating using npm:

 $ npm install openapi-server-url-templating

Usage

openapi-server-url-templating currently supports parsing, validation and substitution. Both parser and validator are based on a superset of ABNF (SABNF) and use apg-lite parser generator.

Parsing

Parsing a Server URL Templating is as simple as importing the parse function and calling it.

import { parse } from 'openapi-server-url-templating';

const parseResult = parse('https://{username}.gigantic-server.com:{port}/{basePath}');
parseResult.result.success; // => true

parseResult variable has the following shape:

{
  result: {
    success: true,
    state: 101,
    stateName: 'MATCH',
    length: 56,
    matched: 56,
    maxMatched: 56,
    maxTreeDepth: 12,
    nodeHits: 758
  },
  ast: fnast {
    callbacks: [
      'server-url-template': [Function: serverUrlTemplate],
      'server-variable': [Function: serverVariable],
      'server-variable-name': [Function: serverVariableName],
      literals: [Function: literals]
    ],
    init: [Function (anonymous)],
    ruleDefined: [Function (anonymous)],
    udtDefined: [Function (anonymous)],
    down: [Function (anonymous)],
    up: [Function (anonymous)],
    translate: [Function (anonymous)],
    setLength: [Function (anonymous)],
    getLength: [Function (anonymous)],
    toXml: [Function (anonymous)]
  }
}
Interpreting AST as list of entries
import { parse } from 'openapi-server-url-templating';

const parseResult = parse('https://{username}.gigantic-server.com:{port}/{basePath}');
const parts = [];

parseResult.ast.translate(parts);

After running the above code, parts variable has the following shape:

[
  [
    'server-url-template',
    'https://{username}.gigantic-server.com:{port}/{basePath}'
  ],
  [ 'literals', 'https://' ],
  [ 'server-variable', '{username}' ],
  [ 'server-variable-name', 'username' ],
  [ 'literals', '.gigantic-server.com:' ],
  [ 'server-variable', '{port}' ],
  [ 'server-variable-name', 'port' ],
  [ 'literals', '/' ],
  [ 'server-variable', '{basePath}' ],
  [ 'server-variable-name', 'basePath' ]
]
Interpreting AST as XML
import { parse } from 'openapi-server-url-templating';

const parseResult = parse('https://{username}.gigantic-server.com:{port}/{basePath}');
const xml = parseResult.ast.toXml();

After running the above code, xml variable has the following content:

<?xml version="1.0" encoding="utf-8"?>
<root nodes="10" characters="56">
  <!-- input string -->
  https://{username}.gigantic-server.com:{port}/{basePath}
  <node name="server-url-template" index="0" length="56">
    https://{username}.gigantic-server.com:{port}/{basePath}
    <node name="literals" index="0" length="8">
      https://
    </node><!-- name="literals" -->
    <node name="server-variable" index="8" length="10">
      {username}
      <node name="server-variable-name" index="9" length="8">
        username
      </node><!-- name="server-variable-name" -->
    </node><!-- name="server-variable" -->
    <node name="literals" index="18" length="21">
      .gigantic-server.com:
    </node><!-- name="literals" -->
    <node name="server-variable" index="39" length="6">
      {port}
      <node name="server-variable-name" index="40" length="4">
        port
      </node><!-- name="server-variable-name" -->
    </node><!-- name="server-variable" -->
    <node name="literals" index="45" length="1">
      /
    </node><!-- name="literals" -->
    <node name="server-variable" index="46" length="10">
      {basePath}
      <node name="server-variable-name" index="47" length="8">
        basePath
      </node><!-- name="server-variable-name" -->
    </node><!-- name="server-variable" -->
  </node><!-- name="server-url-template" -->
</root>

NOTE: AST can also be traversed in classical way using depth first traversal. For more information about this option please refer to apg-js and apg-js-examples.

Validation

Validating a Server URL Templating is as simple as importing the test function and calling it.

import { test } from 'openapi-server-url-templating';

test('https://{username}.gigantic-server.com:{port}/{basePath}'); // => true
test('https://gigantic-server.com/base-path'); // => true
test('https://gigantic-server.com/base-path', { strict: true }); // => false (doesn't contain any server-variable)

Substitution

Substituting a Server URL Templating is as simple as importing the substitute function and calling it.

import { substitute } from 'openapi-server-url-templating';

subtitute('https://{username}.gigantic-server.com', { username: 'char0n' }); // => "https://char0n.gigantic-server.com"

Substituted Server URL Templating is automatically encoded using encodeURIComponent function. It is possible to provide a custom encoder.

import { substitute } from 'openapi-server-url-templating';

substitute('https://{username}.gigantic-server.com', { username: '/?#' }, {
  encoder: (serverVariable) => serverVariable, // no encoding
}); // => "https:///?#.gigantic-server.com"

Grammar

New grammar instance can be created in following way:

import { Grammar } from 'openapi-server-url-templating';

const grammar = new Grammar();

To obtain original ABNF (SABNF) grammar as a string:

import { Grammar } from 'openapi-server-url-templating';

const grammar = new Grammar();

grammar.toString();
// or
String(grammar);

More about OpenAPI Server URL Templating

The Server URL Templating is defined by the following ABNF syntax

; OpenAPI Server URL templating ABNF syntax
server-url-template    = 1*( literals / server-variable )
server-variable        = "{" server-variable-name "}"
server-variable-name   = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
literals               = 1*( %x21 / %x23-24 / %x26 / %x28-3B / %x3D / %x3F-5B
                       / %x5D / %x5F / %x61-7A / %x7E / ucschar / iprivate
                       / pct-encoded)
                           ; any Unicode character except: CTL, SP,
                           ;  DQUOTE, "'", "%" (aside from pct-encoded),
                           ;  "<", ">", "\", "^", "`", "{", "|", "}"

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

pct-encoded    =  "%" HEXDIG HEXDIG
unreserved     =  ALPHA / DIGIT / "-" / "." / "_" / "~"
sub-delims     =  "!" / "$" / "&" / "'" / "(" / ")"
               /  "*" / "+" / "," / ";" / "="

ucschar        =  %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
               /  %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
               /  %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
               /  %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
               /  %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
               /  %xD0000-DFFFD / %xE1000-EFFFD

iprivate       =  %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD

License

openapi-server-url-templating is licensed under Apache 2.0 license. openapi-server-url-templating comes with an explicit NOTICE file containing additional legal notices and information.