@swain-test/simple-schema v2.0.1
This package generates helpful client-side and server-side TypeScript code using simple schemas.
The package also supports generating OpenAPI schemas using the simple schema format.
Installation
yarn add @swain-test/simple-schema
Usage
First, define an API schema file. Schemas look like this:
# schema.yml
Resources:
Post:
type: 'object'
properties:
id:
description: The post's unique identifier.
type: string
message:
description: The post message.
type: string
Endpoints:
POST /posts:
Name: createPost
Request:
type: 'object'
properties:
message: { type: string }
Response:
$ref: '#/definitions/Post'
Next, run some generation.
Axios Client Generation
Use the generate-axios-client
command to generate a nicely typed Axios-based client.
simple-schema generate-axios-client \
--schema schema.yml \
--output generated-client.ts \
--format
The output (in generated-client.ts
):
/* eslint-disable */
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
export type Endpoints = {
'POST /posts': {
Request: {
message: string;
};
Response: Post;
};
};
export type Post = {
/**
* The post's unique identifier.
*/
id: string;
/**
* The post message.
*/
message: string;
};
// ... various helpers ...
export class Client {
constructor(private readonly client: AxiosInstance) {}
createPost(
data: Endpoints['POST /posts']['Request'],
config?: AxiosRequestConfig,
): Promise<AxiosResponse<Endpoints['POST /posts']['Response']>> {
return this.client.request({
...config,
method: 'POST',
data: removePathParams('/posts', data),
url: substituteParams('/posts', data),
});
}
}
Usage:
import axios from 'axios';
import { Client } from './generated-client.ts';
// Provide any AxiosInstance, customized to your needs.
const client = new Client(axios.create({ baseURL: 'https://my.api.com/' }));
const response = await client.createPost({
message: 'some-message',
});
console.log(response.data);
// {
// id: 'some-id',
// message: 'some-message'
// }
API Type Generation
Use the generate-api-types
command to generate helpful types to use for server-side input validation.
simple-schema generate-api-types \
--schema schema.yml \
--output generated-api.ts \
--format
The output (in generated-api.ts
):
/* eslint-disable */
import type { SimpleSchema } from 'simple-schema';
export type Endpoints = {
'POST /posts': {
Request: {
message: string;
};
Response: Post;
};
};
export type Post = {
/**
* The post's unique identifier.
*/
id: string;
/**
* The post message.
*/
message: string;
};
export const Schema: SimpleSchema<Endpoints> = {
// ... the full schema definition, as a JavaScript object.
};
If you're building a Koa app, you can use these generated types with the implementSchema
function to provide a type-safe interface for implementing your API specification:
// app.ts
import Koa from 'koa';
import Router from 'koa-router';
import { implementSchema } from 'simple-schema';
import { APISchema } from './generated-api.ts';
const router = new Router();
implementSchema(APISchema, {
on: router,
parse: (ctx, endpoint, schema, data) => {
// validate that `data` matches `schema`, using whatever
// library you like, and return the parsed response.
},
implementation: {
'POST /posts': (ctx) => {
// `ctx.request.body` is well-typed and has been run-time-validated.
console.log(ctx.request.body.message);
// TypeScript enforces that this matches the `Response` schema.
return { id: '123', message: 'test message' };
},
},
});
const server = new Koa()
.use(router.routes())
.use(router.allowedMethods())
.listen();
OpenAPI Spec generation
Use the generate-open-api-spec
command to generate an OpenAPI spec from a simple schema, which may be useful for interfacing with common OpenAPI tooling.
simple-schema generate-open-api-spec \
--schema schema.yml \
--output openapi-schema.json \
--apiVersion "1.0.0" \
--apiTitle "Simple API" \
--format
The output (in generated-openapi-schema.json
):
{
"openapi": "3.1.0",
"info": {
"version": "Simple API",
"title": "Simple API"
},
"components": {
"schemas": {
"Post": {
"additionalProperties": false,
"properties": {
"id": {
"description": "The post's unique identifier.",
"type": "string"
},
"message": {
"description": "The post message.",
"type": "string"
}
},
"required": ["id", "message"]
}
}
},
"paths": {
"/posts": {
"post": {
"operationId": "createPost",
"responses": {
"200": {
"description": "TODO",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Post"
}
}
}
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
},
"required": ["message"]
}
}
}
}
}
}
}
}
Schema Assumptions
simple-schema
provides a set of JSONSchema assumptions to help simplify Request/Response JSONSchema entries in commonly desired ways.
These assumptions are described by the SchemaAssumptions
type in src/meta-schema.ts
and can be individually or wholly disabled in the Node API and at the command line via the --asssumptions
flag.