API Extensions

Services

When building extensions, you may use internal Directus services directly.

API extensions can directly use internal Directus services like the ItemsService, CollectionsService, FilesService, and more, accessible through the context parameter.

When initializing services, you will need the following:

ParameterDescription
schemaKnex database schema, provided by the getSchema function.
accountabilityAccountability object, used for access control. Omission will use administrator permissions. null will use public permissions.
See a complete list of all services available by looking at the Directus source code.

This page uses endpoints to demonstrate how to use services, but they can also be used in other API extension types

ItemsService

export default (router, context) => {
    const { services, getSchema } = context;
    const { ItemsService } = services;

    router.get('/', async (req, res) => {
        const itemsService = new ItemsService('collection_name', {
            schema: await getSchema(),
            accountability: req.accountability
        });

        // Your route handler logic
    });
};

Create an Item

const data = await itemsService.createOne({
    title: 'Hello world!',
    body: 'This is our first article',
});

Read an Item

const data = await itemsService.readOne('item_id');

Update an Item

const data = await itemsService.updateOne('item_id', {
    title: "An updated title"
});

Delete an Item

const data = await itemsService.deleteOne('item_id');
See a complete list of all methods in the ItemsService by looking at the Directus source code.

CollectionsService

export default (router, context) => {
    const { services, getSchema } = context;
    const { CollectionsService } = services;

    router.get('/', async (req, res) => {
        const collectionsService = new CollectionsService({
            schema: await getSchema(),
            accountability: req.accountability
        });

        // Your route handler logic
    });
};

Create a Collection

const data = await collectionsService.createOne({
    name: 'articles',
    meta: {
        note: 'Blog posts.',
    },
});

Read a Collection

const data = await collectionsService.readOne('collection_name');

Update a Collection

const data = await collectionsService.updateOne('collection_name', {
    meta: {
        note: 'Updated blog posts.',
    },
});

Delete a Collection

const data = await collectionsService.deleteOne('collection_name');
See a complete list of all methods in the CollectionsService by looking at the Directus source code.

FieldsService

export default (router, context) => {
    const { services, getSchema } = context;
    const { FieldsService } = services;

    router.get('/', async (req, res) => {
        const fieldsService = new FieldsService({
            schema: await getSchema(),
            accountability: req.accountability
        });

        // Your route handler logic
    });
}

Create a Field

await fieldsService.createField('collection_name', {
    field: 'title',
    type: 'string',
    meta: {
        icon: 'title',
    },
    schema: {
        default_value: 'Hello World',
    },
});

Read a Field

const data = await fieldsService.readOne('collection_name', 'field_name');

Update a Field

const data = await fieldsService.updateField('collection_name', 'field_name', {
    meta: {
        icon: 'title',
    },
});
You cannot update the field name via Directus after creating the field.

Delete a Field

const data = await fieldsService.deleteField('collection_name', 'field_name');

RelationsService

export default (router, context) => {
  const { services, getSchema } = context;
  const { RelationsService } = services;

  router.get('/', async (req, res) => {
    const relationsService = new RelationsService({
      schema: await getSchema(),
      accountability: req.accountability
    });

    // Your route handler logic
  });
};

Create a Relation

const data = await relationsService.createOne({
    collection: 'articles',
    field: 'featured_image',
    related_collection: 'directus_files',
});

Read a Relation

const data = await relationsService.readOne('collection_name', 'field_name');

Update a Relation

const data = await relationsService.updateOne(
    'collection_name',
    'field_name',
    {
        meta: {
            one_field: 'articles',
        },
    },
);

Delete a Relation

const data = await relationsService.deleteOne('collection_name', 'field_name' );
See a complete list of all methods in the RelationsService by looking at the Directus source code.

FilesService

export default (router, context) => {
    const { services, getSchema } = context;
    const { FilesService } = services;

    router.get('/', async (req, res) => {
        const filesService = new FilesService({
            schema: await getSchema(),
            accountability: req.accountability
        });

        // Your route handler logic
    });
};

Import a File

const assetKey = await filesService.importOne({
    url: file_url,
    data: file_object,
});

Upload a File

Uploading a file requires the use of an external dependency called Busboy, a streaming parser for Node.js. Import it at the top of your extension:

import Busboy from 'busboy'

Then, inside of the route handler, pipe the request into Busboy:

const busboy = Busboy({ headers: req.headers });

busboy.on('file', async (_, fileStream, { filename, mimeType }) => {
    const primaryKey = await filesService.uploadOne(fileStream, {
        filename_download: filename,
        type: mimeType,
        storage: 'local',
    });
});

req.pipe(busboy);

Read a File

const data = await filesService.readOne('file_id');

Update a File

const data = await filesService.updateOne('file_id', { title: 'Random' });

Delete a File

const data = await filesService.deleteOne('file_id');
See a complete list of all methods in the FilesService by looking at the Directus source code.