Directus SDK
The Directus SDK allows to work with Directus directly in your JavaScript and TypeScript projects. The SDK is split into separate modules, giving granular control over which features to include and which can be pruned at build-time. It is lightweight and dependency-free.
npm install @directus/sdk
Create a Client
The Directus SDK is a "Composable Client" that allows you to customize and build a client with the specific features you need. The client starts as an empty wrapper without any functionality. To add features, import and use the following composables:
Composable | Description |
---|---|
rest() | Adds .request() method for making REST requests. |
graphql() | Adds .query() method for making GraphQL requests. |
authentication() | Adds .login() , .logout() , and .refresh() methods. Also adds token handling. |
realtime() | Adds .connect() , .subscribe() , .sendMessage() , and .onWebSocket() methods. Also adds reconnect logic. |
staticToken() | Adds .setToken() and .getToken() methods for manually managing tokens. |
import { createDirectus, rest } from '@directus/sdk';
const directus = createDirectus('http://directus.example.com').with(rest());
Making Requests
To make a request, you must create the client with the rest()
or graphql()
composable. If using rest()
, you must also import and use one of the query functions.
import { createDirectus, rest, readItems } from '@directus/sdk';
const directus = createDirectus('http://directus.example.com').with(rest());
const allPosts = await directus.request(readItems('posts'));
const somePosts = await directus.request(
readItems('posts', {
filter: { status: { _eq: 'published' } },
sort: ['-date_created'],
fields: ['id', 'title', 'date_created'],
limit: 3
})
);
- Imports
createDirectus
is required to create a client.rest
is required to make REST requests, and adds the.request()
method.readItems
is a query function which fetches
- Creating the client
- A new client is created and held in the
directus
variable. createDirectus
requires the valid URL of a Directus project.- The client is created with the
rest()
composable.
- A new client is created and held in the
- Requests
allPosts
makes a request toreadItems
in theposts
collection.somePosts
does the same, but only the specified fields from the latest 3 published items.
Custom Endpoints
To call custom endpoints using the SDK, you can manually provide a path and method. If using TypeScript, you can type the output.
import { createDirectus, rest } from '@directus/sdk';
const directus = createDirectus('http://directus.example.com').with(rest());
const result = await directus.request(() => ({
path: '/custom/endpoint',
method: 'GET',
}));
GraphQL Usage
Add the graphql()
composable to the client, and use the .query()
method.
import { createDirectus, graphql } from '@directus/sdk';
interface Post {
id: number;
title: string;
content: string;
}
interface Schema {
posts: Post[];
}
const directus = createDirectus<Schema>('http://directus.example.com').with(graphql());
const result = await directus.query<Post[]>(`
query {
posts {
id
title
content
}
}
`);
Authentication
The authentication()
composable provides the Directus client with new login()
, logout()
, and refresh()
methods. It also manages token storage and refreshing on your behalf.
import { createDirectus, authentication } from '@directus/sdk';
const directus = createDirectus('http://directus.example.com').with(authentication());
await directus.login(email, password, login_options);
await directus.refresh();
await directus.logout();
This approach will handle refreshing of the token automatically. The current token is stored inside the initialized client.
Login Options
The login options object contains three optional parameters to control the behavior of the request.
type LoginOptions = {
otp?: string;
mode?: AuthenticationMode;
provider?: string;
};
otp
contains the user's one-time-password if two-factor authentication is enabled.mode
defines how the refresh token is returned. One ofjson
,cookie
orsession
. Defaults tocookie
.provider
allows a specific authentication provider to be used. This is unavailable for SSO that relies on browser redirects.
Token Management
Set Token
Import staticToken
and use it when creating a client.
import { createDirectus, staticToken, rest } from '@directus/sdk';
const directus = createDirectus('http://directus.example.com')
.with(staticToken('TOKEN'))
.with(rest());
Get a Token
Import authentication
or staticToken
and use it when creating a client. You now have access to the getToken
method.
import { createDirectus, authentication } from '@directus/sdk';
const directus = createDirectus('http://directus.example.com').with(authentication());
const token = await directus.getToken();
Configure Custom Storage
Internally, getToken()
and setToken()
make use of the configurable storage, which can be customized for your environment's needs. There must be a get()
and set()
method exposed, and the AuthData
type returned.
Instead of storing
AuthData
in an object in the browser, this custom storage implementation stores and retrieves data in localStorage
:import { createDirectus, authentication } from '@directus/sdk';
class LocalStorage {
get() {
return JSON.parse(localStorage.getItem("directus-data"));
}
set(data) {
localStorage.setItem("directus-data", JSON.stringify(data));
}
}
const storage = new LocalStorage();
const directus = createDirectus('http://directus.example.com')
.with(authentication('json', { storage }));
// Set a long term or static token without expiry information.
directus.setToken('TOKEN');
// Set custom credentials to the storage.
storage.set({
access_token: 'token',
refresh_token: 'token',
expires_at: 123456789
});
Cross-Domain Cookies
A common situation is for the Directus backend and frontend to be hosted on different domains, requiring extra configuration to make sure cookies are passed correctly. Usually this is only required for authentication with cookies but this can be set globally for each composable that does requests. This will then apply to all requests made using that composable:
const directus = createDirectus('http://directus.example.com')
.with(authentication('cookie', { credentials: 'include' }))
.with(graphql({ credentials: 'include' }))
.with(rest({ credentials: 'include' }));
Or you can enable this only for specific REST requests using the withOptions
:
const result = await directus.request(
withOptions(refresh(), { credentials: 'include' })
);
Realtime
The Directus SDK makes it easier to work with Realtime by adding .connect()
, .subscribe()
, .sendMessage()
, and .onWebSocket()
methods. It also handles reconnect logic.
Global APIs
To keep the SDK dependency-free, it does rely on the APIs mentioned below, which originally came from the browser ecosystem and may not be available in all environments.
The fetch
API
This API is shipped with almost every modern runtime. Nevertheless, there might be reasons to overwrite or set the implementation, for example, if an alternative implementation is preferred or if you actually work with a special runtime where fetch
is not available.
The URL
API
This API is shipped with almost every modern runtime. However, there are exceptions, like react-native
, that require a polyfill for the SDK to work.
The WebSocket
API
This API is optional if you're not making use of the realtime()
features in the SDK. Backend JavaScript environments often do not ship with an implementation of WebSockets.
The logger
API
This API is optional and currently only used for debugging realtime()
features. This will default to the Console
however in environments where this isn't shipped you can overwrite this with any logger.
Polyfilling
There are two polyfilling approaches, with the first taking precedence.
Options Parameter of createDirectus
import { createDirectus } from '@directus/sdk';
import { ofetch } from 'ofetch';
import WebSocket from 'ws';
const directus = createDirectus('http://directus.example.com', {
globals: {
WebSocket: WebSocket,
fetch: ofetch,
}
});
globalThis
object
import { createDirectus } from '@directus/sdk';
import { ofetch } from 'ofetch';
import WebSocket from 'ws';
globalThis.WebSocket = WebSocket;
globalThis.fetch = ofetch;
import 'react-native-url-polyfill/auto';
const directus = createDirectus('http://directus.example.com');
Polyfill libraries will often register itself to the globalThis
object. For example, the react-native-url-polyfill
package.