Generated API client
As well as using the APIs directly, you can generated a typescript client for your frontend projects to easily work with your APIs with full end to end type safety
Requires version 0.351.0 or higher of the CLI
Generating the client
To generate the client, use the client
command in the CLI from within a Keel project
keel client
This will generate a single file with zero dependancies in your current directory.
To output the client directly into your frontend project you can either pass an output path
keel client --output ../myFrontend/src
or by running the CLI from your frontend project and referencing the Keel directory
keel client -d ../myKeelApp
This will generate a client for the first API in your project. If you have multiple APIs you can specify which API to generate for with the -a apiName
flag
This client uses fetch so will only work in environments where fetch is available
Using the client
First, import APIClient
from the generated file and create a new instance with the deployed url of your project (or the localhost (opens in a new tab) address if running locally)
N.B. This baseUrl
url should include the API name path but not the protocol (e.g. json/rpc/gql)
import { APIClient } from "../keelClient";
const client = new APIClient({
baseUrl: "https://myproject.keelapps.xyz/web/",
});
Navigating the Generated client
The generated client is segmented into three parts, api, client, and ctx.
api
This includes all the actions that you have specified in your Keel schema. For example, if you have an action that lists all users, here is how you can use the generated client to execute this action on the client-side:
const client = new APIClient({
baseUrl: "https://myproject.keelapps.xyz/web/",
});
// use generated client to execute the action on the client-side
const allUsers = await client.api.queries.listUsers()
// log response from API to console
console.log(response.data?.results)
You can also use .api.mutations
if you have actions that mutate data. For example, if you have an action that deletes a user, you can use it like so:
const client = new APIClient({
baseUrl: "https://myproject.keelapps.xyz/web/",
});
// use generated client to execute the action on the client-side
const response = await keel.api.mutations.createUser({ name: name, email: email});
// log response from API to console
console.log(response.data)
client
These are the core client actions that serve as configuration options for the client. They remain consistent across every Keel schema. They include:
setHeaders()
setHeader()
setBaseUrl()
setToken()
clearToken()
ctx
This provides access to user authentication state. It includes the following options:
isAuthenticated: boolean
token: string
Usage:
const client = new APIClient({
baseUrl: "https://myproject.keelapps.xyz/web/",
});
// returns a boolean that represents if a user is authenticated or not
client.ctx.isAuthenticated
// returns the bearer token if available
client.ctx.token
Authenticating
If your API requires authentication, use the authenticate
action as normal and then store the returned token to be used for subsequent requests
const auth = await client.api.mutations.authenticate({
emailPassword: {
email: "me@keel.xyz",
password: "topsecret",
},
createIfNotExists: true,
});
if (auth.error) {
console.log("Auth failed", auth.error.type);
return;
}
console.log("Authenticated");
On logout remember to clear the token
client.client.clearToken();
Error handling
The response of an action is a promise that resolves to an object that either contains the data or an error object
type Data<T> = {
data: T;
error?: never;
};
type Error = {
data?: never;
error: ErrorObj ;
};
type ErrorObj = {
type: "forbidden" | "not_found" | "internal_server_error" | "unknown" | "unauthorized" | "bad_request";
message: string;
requestId?: string; // can be used to access traces in the console
};
You can then check the presence of the error object to handle any errors
const myAction = await client.myAction({
input: "foo"
});
if (myAction.error) {
console.log("Failed", myAction.error.type);
return;
}
const { data } = myAction
// Do things with the data