fluid-oas
Version:
Build declarative OpenApiv3.* specifications.
282 lines (239 loc) • 6.92 kB
Markdown
# Fluid-OAS
Declaratively build _type-safe_ **HTTP APIs** in TypeScript through the **OpenAPI** specification.
## Installation
With npm:
```bash
npm install fluid-oas --save-dev
```
With Bun:
```bash
bun add --development fluid-oas
```
Visit the [docs](https://stoneliucs.github.io/fluid-oas/) here
1. [Overview](#overview)
- [Example Usage](#example-usage)
2. [Schema Design](#schemas)
- [Primitives](#primitive-data-types)
- [Objects](#objects)
- [Arrays](#arrays)
## Overview
_Fluid-OAS_ is an embedded, completely functional _domain specific language_ for expressing type-safe HTTP APIs written in TypeScript through the OpenAPI specification.
- No dependencies, use as is.
- Write the most complex OpenAPI specification you want, use whatever framework you want.
- Focus on core business logic, design systems in an _API-first manner_.
- Leverage TypeScript's advanced type-system to get autocomplete and compile-time checks for building your OpenAPI specification.
- Significantly reduce the amount of boilerplate JSON your team has to write.
### Example Usage
```ts
const info = Info.addTitle("My API")
.addVersion("1.0.0")
.addDescription("Example description.")
.addSummary("Example Summary")
.addContact(
// Add contact information if needed.
Contact.addEmail("youremail@blah.com")
.addName("Your Name.")
.addUrl("https://domain.com")
);
// Example schemas
const nameSchema = Union(
String.addMinLength(1)
.addMaxLength(10)
.addExample(Example.addValue("John"))
.addDescription("Name of the person."),
Null
);
const uuidSchema = String.addFormat("uuid")
.addExample("5e91507e-5630-4efd-9fd4-799178870b10") // Examples are supported but are deprecated as of 3.0.0
.addDescription("Unique identifer");
const userSchema = Object.addProperties({
firstName: nameSchema,
lastName: nameSchema,
id: uuidSchema,
}).addRequired(["id"]); // id is required an should match the id key in the Object.
const errorSchema = Object.addProperties({
message: String.addReadOnly(true),
});
const getUserResponses = Responses.addResponses({
200: Response.addDescription("Successfully Retrieved User!").addContents({
"application/json": MediaType.addSchema(userSchema),
}),
401: Response.addDescription("Failed to retrieve user!").addContents({
"application/json": MediaType.addSchema(errorSchema),
}),
});
// Declare Path Items
const getUser = PathItem.addMethod({
get: Operation.addParameters([
Parameter.schema
.addName("id")
.addIn("path")
.addRequired(true)
.addSchema(uuidSchema),
]).addResponses(getUserResponses),
});
// Register Paths
const path = Path.beginGroup("/api/v1")
.addEndpoints({ "/user/{id}": getUser })
.endGroup();
const oas = OpenApiV3.addOpenApiVersion("3.1.1").addInfo(info).addPaths(path);
// Write OAS Spec
oas.writeOASSync();
```
```json
{
"openapi": "3.1.1",
"info": {
"summary": "Example Summary",
"description": "Example description.",
"title": "My API",
"version": "1.0.0",
"contact": {
"name": "Your Name.",
"url": "https://domain.com",
"email": "youremail@blah.com"
}
},
"paths": {
"/api/v1/user/{id}": {
"get": {
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"description": "Unique identifer",
"example": "5e91507e-5630-4efd-9fd4-799178870b10",
"format": "uuid",
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Successfully Retrieved User!",
"content": {
"application/json": {
"schema": {
"properties": {
"firstName": {
"type": ["string", "null"],
"description": "Name of the person.",
"example": {
"value": "John"
},
"minLength": 1,
"maxLength": 10
},
"lastName": {
"type": ["string", "null"],
"description": "Name of the person.",
"example": {
"value": "John"
},
"minLength": 1,
"maxLength": 10
},
"id": {
"description": "Unique identifer",
"example": "5e91507e-5630-4efd-9fd4-799178870b10",
"format": "uuid",
"type": "string"
}
},
"required": ["id"],
"type": "object"
}
}
}
},
"401": {
"description": "Failed to retrieve user!",
"content": {
"application/json": {
"schema": {
"properties": {
"message": {
"readOnly": true,
"type": "string"
}
},
"type": "object"
}
}
}
}
}
}
}
}
}
```
## Schemas
### Primitive Data types
All schemas are reflective of the latest [Json Schema](https://json-schema.org/understanding-json-schema/reference).
- [number](#defining-a-number)
- [integer](#defining-a-integer)
- [string](#defining-a-string)
- [boolean](#defining-a-boolean)
#### Number
```ts
Number.addDescription("I am a OpenAPI Number!")
.addFormat("double")
.addDefault(1)
.addMinimum(0.5)
.addMaximum(2.5)
.addExclusiveMin(1);
```
```json
{
"type": "number",
"description": "I am a OpenAPI Number!",
"default": 1.5,
"minimum": 0.5,
"maximum": 2.5,
"exclusiveMinimum": true,
"format": "double"
}
```
#### Integer
```ts
Integer.addDescription("I am a OpenAPI Number!")
.addFormat("int32")
.addDefault(1)
.addMinimum(0.5)
.addMaximum(2.5)
.addExclusiveMin(1);
```
#### Defining a String
```ts
String.addDescription("I am an OpenApi String!")
.addDefault("OAS!")
.addMinLength(1)
.addMaxLength(4)
.addPattern(/something/);
```
#### Defining a Boolean
```ts
Boolean.addDescription("I am a OpenAPI boolean!")
.addDefault(false)
.addExample(true);
```
### Objects
Declare properties and other metadata on OpenAPI `Object` with the `addProperties` method.
```ts
Object.addProperties({
firstName: String,
lastName: String,
id: String,
});
```
### Arrays
Arrays can be typed with other schema types, see below for an example of a string array.
```ts
Array.addItems(String)
.addMinItems(1)
.addMaxItems(10)
.addDefault(["defaultVal"]);
```