tapid
v0.0.1
Published
A human-first type framework for describing API services.
Downloads
4
Readme
Tapid
Tapid (TypeScript API Document) is a human-first type framework for describing API services.
Motivation
API documents are essential part of any service design. They help us disover, understand, reason, and test the implementations. Existing API document formats, however, are either machine-generated, archaic, or obsolete algother.
Tapid attempts to solve this problem by providing not a format but a framework on top of TypeScript to describe API services similar to how one would using OpenAPI.
Why TypeScript?
Tapid uses TypeScript as the language to describe APIs. This means you describe your APIs using namespaces, interfaces, and types.
The purpose of any API specification is to describe what a service does: what endpoints it has, what requests it expects, and what responses it returns. Turns out, all of these are types! Instead of inventing yet another specification language, we've decided to rely on the one already used by many—TypeScript.
In addition, using TypeScript for API description has the following benefits:
- Easier adoption. Your team can use the same language they are using already, no need to learn a new one.
- Reusability. You can import your API description anywhere in your code base directly, no generation step needed:
// src/components/Cart.tsx
// 👇 Import the API document.
import type { CartService } from '~/api/services/cart'
interface CartProps {
items: CartService.CartItem[]
// 👆 Reference API types directly
// because it's regular TypeScript!
}
export function Cart(props: CartProps) {
/* ... */
}
- Type-safety. Writing API document in TypeScript means the document itself is type-safe! Tapid provides a framework to make sure the requests and responses you describe actually make sense.
- Rich feature set. Types, references, unions—you get all of TypeScript features for free (and we don't have to design abstractions just to support those).
Example
Here's an example of a cart service API described using Tapid:
// services/user.ts
export declare namespace CartService {
const version = '1.0'
interface Cart {
items: CartItem[]
}
interface CartItem {
id: string
title: string
quantity: number
}
/**
* Return the current cart.
*/
interface GET
extends Endpoint<
'/cart',
{},
{
200: Response.json<Cart>
}
> {}
/**
* Return a cart item by ID.
*/
interface GET
extends Endpoint<
'/cart/:itemId',
{
// Request path parameters are inferred
// from the endpoint URL. Type-safety
// on the specification level!
parameters: { cartId: string }
},
{
// Describe different response scenarios.
200: Response.json<CartItem>
400: Response.text<'Invalid cart ID'>
404: Response.text<'Cart item not found'>
}
> {}
/**
* Add a new item to the cart.
*/
interface POST
extends Endpoint<
'/cart',
{
// Request must provide a FormData representing
// the cart item to add to the cart.
body: Request.formData<CartItem>
},
{
201: Response.json<CartItem>
400: Response.text<'Invalid cart item'>
}
> {}
/**
* Delete a cart item by ID.
*/
interface DELETE
extends Endpoint<
'/cart/:itemId',
{
parameters: { itemId: string }
},
{
200: Response.json<CartItem>
400: Response.text<'Invalid cart ID'>
404: Response.text<'Cart item not found'>
}
> {}
}
Tapid exposes types like
Endpoint
,Request
, andResponse
globally for all of your API documents.