JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 13
  • Score
    100M100P100Q57590F
  • License MIT

Package Exports

  • koas3
  • koas3/lib/koas3.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (koas3) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

OpenAPI v3 implementation for koa

Required peer dependencies

  • @koa/cors
  • @koa/router
  • js-yaml
  • koa
  • koa-body
  • koa-send
  • koas3

npm i @koa/cors @koa/router js-yaml koa koa-body koa-send koas3

Usage example

const fs = require("fs");
const jsyaml = require("js-yaml");
const Koa = require("koa");
const KOAS3 = require("koas3").default;
const http = require("http");
const URL = require("url");

const createApp = async (openapiPath, options) => {
  // create openapi object
  const openapiFile = fs.readFileSync(openapiPath, "utf8");
  const openapi = jsyaml.safeLoad(openapiFile);

  // create Koa app
  const app = new Koa();

  // optionally setup app as proxy
  app.proxy = true;

  // optionaly use default error handler
  app.use(async (ctx, next) => {
    try {
      await next();
      if ([404, 405].includes(ctx.status)) {
        ctx.throw(ctx.status, `Path ${ctx.path} not found`);
      }
    } catch (err) {
      // example of error handling
      if (err.message === "RequestValidationError") {
        const { status, name, message, ...payload } = err;
        ctx.status = typeof err.status === "number" ? err.status : 500;
        ctx.body = {
          statusCode: ctx.status,
          name: "INVALID_SCHEMA",
          description: err.message,
          payload,
        };
      } else {
        // application
        ctx.app.emit("error", err, ctx);
        ctx.status = typeof err.status === "number" ? err.status : 500;
        ctx.body = {
          statusCode: ctx.status,
          name: err.name,
          description: err.message,
          payload: { error: err.message, stack: err.stack, originalError: err },
        };
      }
    }
  });

  // koas3 openapi magic
  const router = await KOAS3(openapi, options);

  // this is important - setup router prefix based on openapi servers
  // depends on your app logic, this just takes the first
  if (openapi.servers && openapi.servers.length) {
    const [serverDefinition] = openapi.servers;
    const url = URL.parse(serverDefinition.url);
    let routePrefix = url.pathname.replace(/\/$/, "") + "/";
    if (serverDefinition.variables) {
      Object.keys(serverDefinition.variables).forEach((k) => {
        routePrefix = routePrefix.replace(
          new RegExp(`{${k}}`, "g"),
          serverDefinition.variables[k].default
        );
      });
    }

    router.prefix(routePrefix);
  }

  // resup KOAS3 router to the app
  app.use(router.routes());
  app.use(router.allowedMethods());

  app.on("error", (err) => {
    // this is any other error handler
    console.error("AppError:", err);
  });

  return app;
};

// run the server
createApp("./openapi.yaml", {
  controllersPath: "./controllers",
})
  .then(async (app) => {
    // make optional database connections

    //mongo.connector(Object.assign({ connect: false }, config.get('mongodb')));
    //await mongo.setup(dbSetup);

    http
      .createServer(app.callback())
      .listen({ port: 9000 }, () => {
        console.log("API is listening on port 9000");
      })
      .on("error", (e) => {
        console.error(`Error starting server: ${e}`);
      });
  })
  .catch(async (e) => {
    console.error("ApiError:", e);
    // stop database connections

    //await mongo.close();
  });