npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

directus-extension-api-docs

v3.0.1

Published

directus extension for swagger interface and openapi including custom endpoints definitions // custom endpoint validations middleware based on openapi or zod

Readme

directus-extension-api-docs

npm version npm downloads license

Compatible with Directus ^9 || ^10 || ^11 and both bundled and non-bundled endpoint extensions.

Release notes: see CHANGELOG.md.

Directus Extension providing:

  • a Swagger UI interface (OpenAPI 3.x)
  • an autogenerated OpenAPI specification file (merged core + your custom endpoints) -- including custom endpoint definitions
  • optional validation middleware for your custom endpoints (based on merged OpenAPI spec). See details below
  • optional Zod-first route definitions for type-safe validation + OpenAPI auto-generation (see Zod-first routes)

workspace

Contents

Prerequisites

You must already have a Directus Node.js project running.

Ref: https://github.com/directus/directus

Installation

npm install directus-extension-api-docs
  • Swagger interface: by default http://localhost:8055/api-docs
  • Openapi documentation: by default http://localhost:8055/api-docs/oas

Configuration (optional)

To include your custom endpoints in the documentation, create an oasconfig.yaml file directly under the /extensions folder (recommended structure). Avoid placing it under /extensions/endpoints unless using Legacy mode.

Options:

  • docsPath optional interface base path (default 'api-docs'). Resulting URLs: /<docsPath> and /<docsPath>/oas.
  • info optional openapi server info (default extract from package.json)
  • tags optional openapi custom tags (will be merged with all standard and all customs tags)
  • publishedTags optional if specified, only operations containing at least one of these tags are kept; all other paths and unused tags are removed.
  • paths optional custom path objects keyed by full path (e.g. /my-custom-path/my-endpoint). These are merged into Directus core paths.
  • components optional custom components (schemas, securitySchemes, etc.) shallow-merged over core components.
  • useAuthentication optional (default false). When true, /api-docs and /api-docs/oas stay publicly reachable: without valid auth they list only anonymous/public paths (no custom endpoints); with auth they list only paths permitted to that user under Directus Access Policies and custom endpoints.

Example below:

docsPath: 'api-docs'
useAuthentication: true
info:
  title: my-directus-bo
  version: 1.5.0
  description: my server description
tags:
- name: MyCustomTag
  description: MyCustomTag description
publishedTags:
- MyCustomTag
components:
  schemas:
    UserId:
      type: object
      required:
      - user_id
      x-collection: directus_users
      properties:
        user_id:
          description: Unique identifier for the user.
          example: 63716273-0f29-4648-8a2a-2af2948f6f78
          type: string

Definitions (optional)

For each endpoint extension, you can define OpenAPI partials by adding an oas.yaml file in the root of that endpoint's folder.

Non-bundled extensions

Place the oas.yaml file directly in the extension folder:

- ./extensions/
  ─ oasconfig.yaml (optional)
  - my-endpoint-extension/
    - oas.yaml

Bundled extensions

For bundled extensions, place oas.yaml files in each sub-extension's folder under the src directory:

- ./extensions/
  ─ oasconfig.yaml (optional)
  - my-bundle-extension/
    - src/
      - routes-endpoint/
        - oas.yaml
      - admin-endpoint/
        - oas.yaml

This structure follows Directus's standard bundle architecture where each sub-extension (routes, endpoints, hooks, etc.) has its own folder under src/. The extension will automatically discover and merge all oas.yaml files from these subdirectories.

Mixed environments

Both bundled and non-bundled extensions can coexist in the same project. The extension will automatically detect and merge all oas.yaml files from both types.

Properties:

  • tags optional openapi custom tags
  • paths optional openapi custom paths
  • components optional openapi custom components

Example below (./extensions/my-endpoint-extensions/oas.yaml):

tags:
- name: MyCustomTag2
  description: MyCustomTag description2
paths:
  "/my-custom-path/my-endpoint":
    post:
      security:
        - Auth: [ ]
      summary: Validate email
      description: Validate email
      tags:
        - MyCustomTag2
        - MyCustomTag
      requestBody:
        content:
          application/json:
            schema:
              "$ref": "#/components/schemas/UserId"
      responses:
        '200':
          description: Successful request
          content:
            application/json:
              schema:
                "$ref": "#/components/schemas/Users"
        '401':
          description: Unauthorized
          content: {}
        '422':
          description: Unprocessable Entity
          content: {}
        '500':
          description: Server Error
          content: {}
components:
  schemas:
    Users:
      type: object # ref to standard components declaring it empty
  securitySchemes:
    Auth:
      in: header
      name: Authorization
      type: apiKey

Legacy mode

Configuration and definitions can also be managed in this legacy structure (still supported, but prefer the simplified root placement):

- ./extensions/
  - endpoints/
    - oasconfig.yaml
    - my-endpoint-extensions/
      - oas.yaml
    - my-endpoint-extensions2/
      - oas.yaml

Validations (optional)

You can enable a request validation middleware based on your merged custom definitions.

Call the validate function inside your custom endpoint source (./extensions/my-endpoint-extensions/src/index.js).

Arguments: validate(router, services, schema, paths?). paths (optional array) lets you restrict validation to only specific path keys from oasconfig.yaml instead of all custom paths.

Example below:

const { validate } = require('directus-extension-api-docs')

export default {
    id: 'my-custom-path',
    handler: async (router, { services, getSchema }) => {
        const schema = await getSchema();
        await validate(router, services, schema); // Enable validator

        router.post('/my-endpoint', async (req, res, next) => {
            ...
        })
    },
}

Zod-first routes (optional)

An alternative ergonomic API: declare schemas and handlers together. The OpenAPI fragment is generated and merged into the same spec served at /api-docs/oas, and request validation runs automatically before each handler. Everything you need ships from this package — no need to import defineEndpoint from the Directus SDK.

const { defineEndpoint, z, registerSchema } = require('directus-extension-api-docs');

const UserId = registerSchema(
    'UserId',
    z.object({
        user_id: z.string().uuid().openapi({ example: '63716273-0f29-4648-8a2a-2af2948f6f78' }),
    }),
);

module.exports = defineEndpoint('my-custom-path', (route, { services, getSchema }) => {
    route({
        method: 'post',
        path: '/my-endpoint',
        tags: ['MyCustomTag'],
        summary: 'Validate user id',
        security: [{ Auth: [] }],
        request: { body: UserId },
        responses: {
            200: { description: 'OK', schema: UserId },
            401: { description: 'Unauthorized' },
        },
        handler: async (req, res) => {
            // req.body is typed: { user_id: string }
            res.json({ user_id: req.body.user_id });
        },
    });
});

Notes:

  • The OpenAPI prefix defaults to /<id> so paths in /api-docs/oas match the URLs clients actually call (Directus mounts each endpoint extension under /<id>).
  • services, getSchema, logger, ... are available in the setup closure and naturally accessible from each handler.
  • For finer control (e.g. mixing Zod and raw Express routes), the lower-level defineRoute(router, config) is still exported.

Public exports (named exports of the package main, alongside validate):

| Export | Purpose | | ----------------- | -------------------------------------------------------------------------------- | | defineEndpoint | Declarative wrapper for a Directus endpoint extension built on Zod routes. | | defineRoute | Lower-level route registration when you already have your own router. | | registerSchema | Register a reusable Zod schema as components.schemas.<name> (emits $ref). | | z | Re-exported zod already extended with .openapi() metadata. | | zodValidator | The per-slot validation middleware used internally, for advanced use. |

Validation errors are returned as HTTP 400 with the same { message, errors[] } envelope used by express-openapi-validator, so existing API consumers don't need to change. Coexists with YAML definitions: pick whichever fits each endpoint.

YAML vs Zod

Both pipelines feed the same /api-docs/oas document and can be mixed per endpoint.

  • YAML (oasconfig.yaml + oas.yaml): preferred when the OpenAPI spec is the source of truth, or when you import an existing spec. Runtime validation is opt-in via validate(...).
  • Zod: preferred when you want one source of truth that also types req.body / req.params / req.query and validates by default. No separate YAML file to keep in sync.

Contributing

Issues and pull requests are welcome. See CONTRIBUTING.md for setup, scripts, and commit conventions.

Reporting issues

Bugs and feature requests: github.com/sacconazzo/directus-extension-api-docs/issues.

For security vulnerabilities, please follow SECURITY.md instead of opening a public issue.

License

MIT © Giona Righini (sacconazzo)