Usage
API def provides a unified way to type your endpoints allowing for compile time checking of query, body, response and even url parameters.
Getting Started
npm i api-def
First we define our base API and give it a base URL which is the root path of your remote service:
import {Api} from "api-def";
const api = new Api({
name: "My Backend",
baseUrl: "http://localhost:5000/v1",
});
export default api;
Defining Endpoints
Now let's define some endpoints we can call! Let's start with a simple definition of a health check endpoint:
export const fetchHealthCheck = api.endpoint()
.responseOf<{ success: boolean; }>()
.build({
id: "fetch_health_check",
path: "/status/health-check",
method: "get",
// optional
name: "Health Check",
description: "Returns success as true",
});
You can see that we give the endpoint an id
, path
and method
. The path
will be appended to the baseUrl
in our API object.
We can also provide optional name
and description
which will help document our API and can be used in dev tools ect.
Calling an Endpoint
To call our endpoint we can use the submit
function, which will GET
the URL http://localhost:5000/v1/status/health-check
:
const makeRequest = async () => {
const res = await fetchHealthCheck.submit({});
return res.data.success; // true
};
Typing Body, Query & Params
In most cases we will want to make more complex requests, for example fetching and updating user information. Using api-def
you can also type the query, body and URL params that you pass in when you want to make one of these queries:
interface UserData {
firstName: string;
age: number;
}
export const fetchUser = api.endpoint()
.paramsOf<"uid">()
.responseOf<UserData & { id: string }>()
.build({
id: "fetch_user",
name : "Fetch User",
description: "Fetch a user, will respond with error code 'auth/permission-denied' if unauthorized",
path : "/user/:uid",
method : "get",
});
When calling this endpoint, it is verified that all params are resolved in the path:
const res = await fetchUser.submit({
params: {
uid: "exampleId"
}
});
return res.data // { uid: "exampleId", firstName: "Hello World", age: 22 }
Now let's add the endpoint to update a user and see how we can type our body:
export const updateUser = api.endpoint()
.paramsOf<"uid">()
.bodyOf<{ data: Partial<UserData> }>()
.responseOf<UserData & { id: string }>()
.build({
id: "update_user",
name : "Update User",
description: "Updates a user, will respond with error code 'auth/permission-denied' if unauthorized",
path : "/user/:uid",
method : "post",
});
const res = await updateUser.submit({
params: {
uid: "exampleId"
},
body: {
data: {
firstName: "Test"
}
}
});
return res.data // { uid: "exampleId", firstName: "Test", age: 22 }
Setting Expected Return Statuses
By default a successful call is one that returns a status of 200
to 299
. You can override this in the endpoint config with a combination of ranges, and single values.
export const fetchHealthCheck = api.endpoint()
.responseOf<{ success: boolean; }>()
.build({
id: "fetch_health_check",
name : "Health Check",
description: "Returns success as true",
path : "/status/health-check",
method : "get",
config : {
acceptableStatus : [[301, 302], 200],
},
});