apigen-ts
v1.0.1
Published
Simple typed OpenAPI client generator
Downloads
992
Maintainers
Readme
apigen-ts
Features
- Generates ready to use
ApiClient
with types (usingfetch
) - Single output file, minimal third-party code
- Loads schemas from JSON / YAML, locally and remote
- Ability to customize
fetch
with your custom function - Automatic formating with Prettier
- Can parse dates from date-time format (
--parse-dates
flag) - Support OpenAPI v2, v3, v3.1
- Can be used with npx as well
Install
yarn install -D apigen-ts
Usage
1. Generate
# From url
yarn apigen-ts https://petstore3.swagger.io/api/v3/openapi.json ./api-client.ts
# From file
yarn apigen-ts ./openapi.json ./api-client.ts
Run yarn apigen-ts --help
for more options. Examples of generated clients here.
2. Import
import { ApiClient } from "./api-client"
const api = new ApiClient({
baseUrl: "https://example.com/api",
headers: { Authorization: "secret-token" },
})
3. Use
// GET /pet/{petId}
await api.pet.getPetById(1) // -> Pet
// GET /pet/findByStatus?status=sold
await api.pet.findPetsByStatus({ status: "sold" }) // -> Pets[]
// PUT /user/{username}; second arg body with type User
await api.user.updateUser("username", { firstName: "John" })
Advanced
Login flow
const { token } = await api.auth.login({ usename, password })
api.Config.headers = { Authorization: token }
await api.protectedRoute.get() // here authenticated
Automatic date parsing
yarn apigen-ts ./openapi.json ./api-client.ts --parse-dates
const pet = await api.pet.getPetById(1)
const createdAt: Date = pet.createdAt // date parsed from string with format=date-time
Errors handling
An exception will be thrown for all unsuccessful return codes.
try {
const pet = await api.pet.getPetById(404)
} catch (e) {
console.log(e) // parse error depend of your domain model, e is awaited response.json()
}
Also you can define custom function to parse error:
class MyClient extends ApiClient {
async ParseError(rep: Response) {
// do what you want
return { code: "API_ERROR" }
}
}
try {
const api = new MyClient()
const pet = await api.pet.getPetById(404)
} catch (e) {
console.log(e) // e is { code: "API_ERROR" }
}
Base url resolving
You can modify how the endpoint url is created. By default URL constructor used to resolve endpoint url like: new URL(path, baseUrl)
which has specific resolving rules. E.g.:
new URL("/v2/cats", "https://example.com/v1/") // -> https://example.com/v2/cats
new URL("v2/cats", "https://example.com/v1/") // -> https://example.com/v1/v2/cats
If you want to have custom endpoint url resolving rules, you can override PrepareFetchUrl
method. For more details see issue.
class MyClient extends ApiClient {
PrepareFetchUrl(path: string) {
return new URL(`${this.Config.baseUrl}/${path}`.replace(/\/{2,}/g, "/"))
}
}
const api = new MyClient({ baseUrl: "https://example.com/v1" })
// will call: https://example.com/v1/pet/ instead of https://example.com/pet/
const pet = await api.pet.getPetById(404)
Node.js API
Create file like apigen.mjs
with content:
import { apigen } from "apigen-ts"
await apigen({
source: "https://petstore3.swagger.io/api/v3/openapi.json",
output: "./api-client.ts",
// everything below is optional
name: "MyApiClient", // default "ApiClient"
parseDates: true, // default false
resolveName(ctx, op, proposal) {
// proposal is [string, string] which represents module.funcName
if (proposal[0] === "users") return // will use default proposal
const [a, b] = op.name.split("/").slice(3, 5) // eg. /api/v1/store/items/search
return [a, `${op.method}_${b}`] // [store, 'get_items'] -> apiClient.store.get_items()
},
})
Then run with: node apigen.mjs
Usage with different backend frameworks
FastAPI
By default apigen-ts
generates noisy method names when used with FastAPI. This can be fixed by custom resolving for operations ids.
from fastapi import FastAPI
from fastapi.routing import APIRoute
app = FastAPI()
# add your routes here
def update_operation_ids(app: FastAPI) -> None:
for route in app.routes:
if isinstance(route, APIRoute):
ns = route.tags[0] if route.tags else "general"
route.operation_id = f"{ns}_{route.name}".lower()
# this function should be after all routes added
update_operation_ids(app)
Note: If you want FastAPI to be added as preset, open PR please.
Compare
- openapi-typescript-codegen (npm): no single file mode #1263
- openapi-typescript (npm): low level api; no named types export to use in client code
- openapi-generator-cli (npm): wrapper around java lib
- swagger-typescript-api (npm): complicated configuration; user-api breaking changes between versions
Development
- https://ts-ast-viewer.com
- https://jsonschemalint.com
- https://redocly.github.io/redoc/
- https://swagger.io/docs/specification/basic-structure/