Skip to content

Latest commit

 

History

History
317 lines (269 loc) · 11.6 KB

http-client-for-oas-operations.md

File metadata and controls

317 lines (269 loc) · 11.6 KB

HTTP client for OAS operations

HTTP client for OAS operations is an OpenAPI specific HTTP client for OAS operations. It maps an OAS operation and values into an HTTP request.

To execute an OAS operation, you need to provide HTTP client for OAS operations with various properties.

Type notations are formatted like so:

  • String="" means a String type with a default value of "".
  • String=["a"*, "b", "c", "d"] means a String type that can be a, b, c, or d, with the * indicating that a is the default value.
Property Description
spec Object, REQUIRED. OpenAPI definition represented as POJO.
operationId String. Unique string used to identify an operation. If not provided, pathName + method must be used instead.
pathName String. OpenAPI defines a unique operation as a combination of a path and an HTTP method. If operationId is not provided, this property must be set.
method String=["GET", "HEAD", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH"]. OpenAPI defines a unique operation as a combination of a path and an HTTP method. If operationId is not provided, this property must be set.
parameters Object. Parameters object, eg: { q: 'search string' }. Parameters not defined in spec will be ignored.
parameterBuilders Object=null. When provided in shape of { body: Function, header: Function, query: Function, path: Function, formData: Function }, it can fully conltrol how parameters of various types are built. This library comes with two default parameter builders: OpenAPI 2.x builders and OpenAPI 3.0.x builders.
securities Object. Maps security schemes to a request. Securities not defined in spec will be ignored.

Examples

Bearer: { authorized: { BearerAuth: {value: "3492342948239482398"} } }

Basic: { authorized: { BasicAuth: { username: 'login', password: 'secret' } } }

ApiKey: { authorized: { ApiKey: { value: '234934239' } } }

oAuth2: { authorized: { oAuth2: { token: { access_token: '234934239' } } } }
requestInterceptor Function=identity. Either synchronous or asynchronous function transformer that accepts Request and should return Request.
responseInterceptor Function=identity. Either synchronous or asynchronous function transformer that accepts Response and should return Response.
requestContentType String. Sets appropriate media type for request body, e.g. application/json. If supplied media type is not defined for the request body, this property is ignored.
responseContentType String. Expect appropriate media type response, e.g. application/json. Creates an Accept header in Request object.
attachContentTypeForEmptyPayload Boolean=false. Attaches a Content-Type header to a Request even when no payload was provided for the Request.
http Function=Http. A function with an interface compatible with HTTP Client.
userFetch Function=cross-fetch. Custom asynchronous fetch function that accepts two arguments: the url and the Request object and must return a Response object. More info in HTTP Client documentation.
signal AbortSignal=null. AbortSignal object instance, which can be used to abort a request as desired.
server String. URL (https://example.com) or relative URI Reference (/path/subpath). Must match with of the defined Server Objects. If matched, it will be prepended to every requested path.
contextUrl String. URL, e.g. https://example.com. Used in following situations:

If server option is not matched and there is no Server Object defined in the definition, this URL will be prepended to every requested path.

If matched Server Object is defined as relative URI Reference its url fixed field is resolved against contenxtUrl. Resolved URL will be prepended to every requested path.

For all later references, we will always use following OpenAPI 3.0.0 definition when referring to a spec.

openapi: 3.0.0
info:
  title: Testing API
  version: 1.0.0
components:
  schemas:
    user:
      properties:
        id:
          type: integer
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
    ApiKey:
      type: apiKey
      in: header
      name: X-API-KEY
    BearerAuth:
      type: http
      scheme: bearer
    oAuth2:
      type: oauth2
      flows:
        implicit:
          authorizationUrl: 'https://api.example.com/oauth2/authorize'
          scopes:
            read: authorize to read
servers:
  - url: 'http://localhost:8080'
  - url: '/'  
paths:
  /users:
    get:
      operationId: getUserList
      description: Get list of users
      security:
        - BasicAuth: []
          BearerAuth: []
          ApiKey: []
          oAuth2: []
      parameters:
        - name: q
          in: query
          description: search query parameter
          schema:
            type: array
            items:
              type: string
          style: pipeDelimited
          explode: false  
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/user'

Use swagger editor to convert this YAML OpenAPI definition to JSON; File -> Convert and save as JSON. We'll assign this JSON to variable called pojoDefinition and use it in later examples.

Above OpenAPI definitions describes following API implemented in node.js:

const http = require('http');

const getUserList = (req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.writeHead(200);
  res.end('[{"id":"value"}]');
};

const requestListener = (req, res) => {
  if (req.url.startsWith('/users')) {
    getUserList(req, res);
  } else {
    res.setHeader('Content-Type', 'text/plain');
    res.writeHead(404);
    res.end('Not found');
  }
};

const server = http.createServer(requestListener);
server.listen(8080);

Executing an operation

Executing an OAS operation is as simple as calling SwaggerClient.execute static method.

Using operationId

import SwaggerClient from 'swagger-client';

SwaggerClient.execute({
  spec: pojoDefinition,
  operationId: 'getUserList',
  // Parameters that accepts multiple values are provided as arrays ['search1', 'search2'].
  // ['search1', 'search2'] will result results in `?q=search1|search2`
  // depending on serialization options defined by `style` and `explode`.
  parameters: { q: 'search string' }, 
  securities: { authorized: { BearerAuth: "3492342948239482398" } },
}); // => Promise.<Response>

Using unique pathName + method combination

import SwaggerClient from 'swagger-client';

SwaggerClient.execute({
  spec: pojoDefinition,
  pathName: '/users',
  method: 'get',
  parameters: { q: 'search string' },
  securities: { authorized: { BearerAuth: "3492342948239482398" } },
}); // => Promise.<Response>

Using server option

We can use server option to pick one of the defined Server Objects in the definition to send requests against.

SwaggerClient.execute({
  spec: pojoDefinition,
  operationId: 'getUserList',
  parameters: { q: 'search string' }, 
  securities: { authorized: { BearerAuth: "3492342948239482398" } },
  server: 'http://localhost:8080',
}); // => Promise.<Response>

Using contextUrl as fallback

We can use contextUrl in case when no Server Objects are defined in the definition, or the Server Objects are defined as relative URI References.

SwaggerClient.execute({
  spec: pojoDefinition,
  operationId: 'getUserList',
  parameters: { q: 'search string' }, 
  securities: { authorized: { BearerAuth: "3492342948239482398" } },
  server: '/',
  contextUrl: 'https://example.com', 
}); // => Promise.<Response>

Request cancellation with AbortSignal

You may cancel requests with AbortController. The AbortController interface represents a controller object that allows you to abort one or more Web requests as and when desired. Using AbortController, you can easily implement request timeouts.

Node.js

AbortController needs to be introduced in Node.js environment via abort-controller npm package.

const SwaggerClient = require('swagger-client');
const AbortController = require('abort-controller');

const controller = new AbortController();
const { signal } = controller;
const timeout = setTimeout(() => {
  controller.abort();
}, 1);

(async () => {
  try {
    await SwaggerClient.execute({
      spec,
      pathName: '/users',
      method: 'get',
      parameters: { q: 'search string' },
      securities: { authorized: { BearerAuth: "3492342948239482398" } },
      signal,
    });
  } catch (error) {
    if (error.name === 'AbortError') {
      console.error('request was aborted');
    }
  } finally {
    clearTimeout(timeout);
  }
})();
Browser

AbortController is part of modern Web APIs. No need to install it explicitly.

<html>
  <head>
    <script src="//unpkg.com/swagger-client"></script>
    <script>
        const controller = new AbortController();
        const { signal } = controller;
        const timeout = setTimeout(() => {
          controller.abort();
        }, 1);

        (async () => {
          try {
            await SwaggerClient.execute({
              spec,
              pathName: '/users',
              method: 'get',
              parameters: { q: 'search string' },
              securities: { authorized: { BearerAuth: "3492342948239482398" } },
              signal,
            });
          } catch (error) {
            if (error.name === 'AbortError') {
              console.error('request was aborted');
            }
          } finally {
            clearTimeout(timeout);
          }
        })();
    </script>
  </head>
  <body>
    check console in browser's dev. tools
  </body>
</html>

Alternate API

It's also possible to call execute method from SwaggerClient instance.

import SwaggerClient from 'swagger-client';

new SwaggerClient({ spec: pojoDefinition, authorizations: { BearerAuth: "3492342948239482398" } })
  .then(
    client => client.execute({
      operationId: 'getUserList',
      parameters: { q: 'search string' },
    })
  ); // => Promise.<Response>

Building a Request

You can build a Request object from an OAS operation and feed it later to the HTTP Client.

import SwaggerClient from 'swagger-client';

const request = SwaggerClient.buildRequest({
  spec: pojoDefinition,
  operationId: 'getUserList',
  parameters: { q: 'search string' },
  securities: { authorized: { BearerAuth: "3492342948239482398" }},
  responseContentType: 'application/json',
});
/*
 * {
 *   url: 'http://localhost:8080/users?q=search%20string',
 *   credentials: 'same-origin',
 *   headers: {
 *     accept: 'application/json',
 *     Authorization: 'Bearer 3492342948239482398'
 *   },
 *   method: 'GET'
 * }
 */

SwaggerClient.http(request); // => Promise.<Response>