ts-cactus
v1.0.82
Published
Create Typescript types from Open API Specification 3 (OAS3)
Downloads
1,738
Readme
ts-cactus
Create Typescript types from Open API Specification 3 (OAS3)
Features:
- ✅ Convert OAS3 to Typescript
- ✅ Typesafe API
- ✅ Svelte Adapter
- ✅ Works in any client ecosystem
- ✅ Lightweight
- ✅ IDE Autocompletion
Quick Start
Install ts-cactus 👇
bun add ts-cactus
Add to your package.json 👇 Make sure the "lib" folder exists, if not, create it.
{
"name": "client-site",
"private": true,
"type": "module",
"scripts": {
"gen-users": "bun run ./node_modules/.bin/ts-cactus --url OAS3_JSON_URL --to ./src/lib/usersSchema.ts",
"gen-accounts": "bun run ./node_modules/.bin/ts-cactus --url OAS3_JSON_URL --to ./src/lib/accountsSchema.ts",
"gen-all": "bun run gen-users && bun run gen-accounts"
}
}
Generate two schemas 👇
bun run gen-all
Create services.ts file in any place of the src directory 👇
import { createApi } from "ts-cactus";
import { apiSchema as usersSchema } from "./usersSchema.ts";
import { apiSchema as accountsSchema } from "./accountsSchema.ts";
const users = createApi("https://domain.com", usersSchema);
const accounts = createApi("https://domain.com", accountsSchema);
export const services = { users, accounts };
In your api.ts 👇
import { services } from "./services.ts";
const getUsers = async () => {
const [status, res] = await services.users.get.users({
page: 1,
perPage: 20,
});
if (status) {
console.log(res); // response
} else {
console.log(res); // error
}
};
Svelte
Usage, here is an example component with an adapter for svelte, but you can use any other framework 👇
<script lang="ts">
import { load } from "ts-cactus/svelte";
import { services } from "./lib/services.ts";
let params = {
page: 1,
};
const getAccounts = async () => {
return await services.accounts.get.adminAccounts(params);
};
let accounts = load(getAccounts);
</script>
<button
on:click="{() => {
$accounts.res = undefined;
$accounts.reload();
}}">Reload</button
>
<button
on:click="{() => {
params.page += 1;
$accounts.reload();
}}">Next</button
>
{#if $accounts?.loading}
Loading
{/if}
{#each $accounts?.res?.data || [] as account}
<div>
<span>{account.clientName}</span>
</div>
{/each}
Adapter - load function is needed just for convenient data getting, it’s not required to use this function. However, if you use load, you must set the following option in your tsconfig.json: "moduleResolution": "nodenext".
You can also add events for more control 👇
const users = createApi("https://domain.com", usersSchema, {
beforeRequest: async (request) => {
console.log(request.headers.get("header"));
// set request headers: req.headers.append("xxx", "value")
},
afterRequest: async (request, response) => {
// logic
},
});
Need to abort the request? Easy! 👇
const getAccounts = async () => {
const controller = new AbortController();
const signal = controller.signal;
window.setTimeout(() => {
controller.abort();
}, 2000);
return await services.accounts.get.adminAccounts(params, {
signal,
});
};
Any method has options where you can pass a signal.
Upload File 👇
const doc1 = await fetch("doc.pdf");
const doc2 = new File([], "test");
// uploadPassport - multipart/form-data
await services.accounts.post.uploadPassport({
file: await doc1.blob(), // good type
});
// uploadPassport - multipart/form-data
await services.accounts.post.uploadPassport({
file: doc2, // good type
});
You don't need to wrap in try/catch 👇
const createUser = async () => {
const [status, res] = await services.users.post.createUser({...});
console.log(status, res);
}
Author
Released under the MIT License.