OpenAPI

OpenAPI endpoints are created by setting up an <openapi /> webrule.

Setup

To add a new endpoint:

Setting up an authorization callback is required to prevent a typo/parsing error from removing all security on your API. The authorization callback can be defined at the toplevel or at any path or operation level - the most specific handler will be used. If no callback is set up, all API calls will return a 403 Forbidden error.

An operation without an implementation function will still validate parameters and authorization but return a 501 Not implemented when otherwise properly invoked.

Authorization functions should have the following signature: export async function auth(req: RestRequest): Promise<RestAuthorizationResult>

Implementation functions should have the following signature: export async function impl(req: RestRequest): Promise<WebReponse>

After setting up the above rules you should be able to access the 'openapi.json' document below the specified API path. Eg if you defined your API as follows:

<moduledefinition> 
  <services>
    <openapiservice name="myapp" spec="openapi/myapp/myapp.yml" />
…
  <backend> 
    <openapi path="root:myapp/1/" service="myapp" />

You should be able to see your API on https://my.webhare.dev/myapp/1/openapi/openapi.json. Both this file and a Swagger-UI are linked by default from the root of your API (eg https://my.webhare.dev/myapp/1/)

Examples

A minimal openapi.yml file:

---
openapi: 3.0.2
info:
  title: My API
  version: 1.0.0

x-webhare-authorization: openapi.ts#needSecret

servers:
- url: "."
  description: API Server

paths:
  "/dummy":
    get:
      responses:
        "200":
          description: A dummy
      x-webhare-implementation: openapi.ts#getDummy

The accompanying openapi.ts file:

import { createJSONResponse, RestAuthorizationResult, RestRequest } from "@webhare/router";

export async function needSecret(req: RestRequest): Promise<RestAuthorizationResult> {
  return { authorized: req.webrequest.headers.get("x-key") === "secret", authorized: null };
}

export async function getDummy(req: RestRequest) {
  return createJSONResponse({ answer: 42 });
}