
Security News
CVE Volume Surges Past 48,000 in 2025 as WordPress Plugin Ecosystem Drives Growth
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.
@gravity-ui/expresskit-api
Advanced tools
This package provides OpenAPI/Swagger integration for ExpressKit, automatically generating API documentation from your route contracts and authentication handlers.
Add the integration to an existing ExpressKit project:
npm install @gravity-ui/expresskit-api
Wrap your routes before passing them to ExpressKit:
Simple approach (without global auth handlers):
import {
ExpressKit,
withContract,
AppRoutes,
RouteContract,
AuthPolicy,
} from '@gravity-ui/expresskit';
import {NodeKit} from '@gravity-ui/nodekit';
import {z} from 'zod';
import {createOpenApiRegistry, bearerAuth, apiKeyAuth} from '@gravity-ui/expresskit-api';
const {registerRoutes} = createOpenApiRegistry({title: 'Super API'});
const apiKeyHandler = apiKeyAuth(
'apiKeyAuth', // scheme name
'header', // location: 'header', 'query', or 'cookie'
'X-API-Key', // parameter name
['read:items'], // optional scopes
)(function authenticate(req, res, next) {
const apiKey = req.headers['x-api-key'];
if (apiKey !== 'valid_api_key') {
res.status(401).json({error: 'Unauthorized: Invalid API key'});
return;
}
next();
});
const CreateItemConfig = {
operationId: 'createItem',
summary: 'Create a new item',
tags: ['Items'],
request: {
body: z.object({
itemName: z.string().min(3, 'Item name must be at least 3 characters long'),
quantity: z.number().int().positive('Quantity must be a positive integer'),
}),
},
response: {
content: {
201: z.object({
itemId: z.string(),
itemName: z.string(),
quantity: z.number().positive(),
}),
},
},
} satisfies RouteContract;
const createItemHandler = withContract(CreateItemConfig)(async (req, res) => {
const {itemName, quantity} = req.body;
const newItem = {
itemId: `item_${Date.now()}`,
itemName,
quantity,
};
res.sendTyped(201, newItem);
});
export const routes: AppRoutes = {
'POST /items': {
handler: createItemHandler,
authHandler: apiKeyHandler,
authPolicy: AuthPolicy.required,
},
};
const app = new ExpressKit(nodekit, registerRoutes(routes, nodekit));
app.run(); // Open http://localhost:3030/api/docs
Using setup parameter (with global auth handlers support):
import {
ExpressKit,
withContract,
AppRoutes,
RouteContract,
AuthPolicy,
} from '@gravity-ui/expresskit';
import {NodeKit} from '@gravity-ui/nodekit';
import {z} from 'zod';
import {createOpenApiRegistry, bearerAuth} from '@gravity-ui/expresskit-api';
const {registerRoutes} = createOpenApiRegistry({title: 'Super API'});
// Global auth handler configured in NodeKit
const globalAuthHandler = bearerAuth('jwtAuth')(function authenticate(req, res, next) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (token !== 'valid_token') {
res.status(401).json({error: 'Unauthorized'});
return;
}
next();
});
const nodekit = new NodeKit({
config: {
appAuthHandler: globalAuthHandler,
appAuthPolicy: AuthPolicy.required,
},
});
const routes: AppRoutes = {
'POST /items': {
handler: createItemHandler,
// No authHandler specified - will use global appAuthHandler
},
};
// Use setup parameter to access nodekit context
const app = new ExpressKit(nodekit, registerRoutes(routes, nodekit));
app.run(); // Open http://localhost:3030/api/docs
createOpenApiRegistry(config?: OpenApiRegistryConfig) tunes both the generated schema and the Swagger UI mount. Key options:
| Field | Default | Description |
|---|---|---|
title | "API Documentation" | Top-level title shown in the UI. |
version | "1.0.0" | Populates info.version. |
description | "Generated API documentation" | Short blurb under the title. |
contact | undefined | {name, email, url} for ownership info. |
license | undefined | {name, url} displayed in the footer. |
servers | [ { url: 'http://localhost:3030' } ] | Servers array for the spec dropdown. |
swaggerUi | {} | Passed straight to swagger-ui-express (customCss, explorer, themes, …). |
enabled | true | Convenience flag—skip calling registerRoutes if you want to hide docs. |
path | '/api/docs' | Mount path for Swagger UI; value is used as-is. |
swaggerJsonPath | undefined | Path relative to mount path where OpenAPI schema is served as JSON. When set, Swagger UI loads the schema from this endpoint instead of embedding it directly. |
Usage example:
const {registerRoutes} = createOpenApiRegistry({
title: 'Super API',
description: 'Internal platform endpoints',
servers: [{url: 'https://api.example.com'}],
swaggerUi: {
explorer: true,
customCss: '.topbar { display: none; }',
},
});
Using swaggerJsonPath for async schema loading:
const {registerRoutes} = createOpenApiRegistry({
title: 'Super API',
path: '/api/docs',
swaggerJsonPath: '/swagger.json', // Relative to mount path
});
// The schema will be available at /api/docs/swagger.json
// Swagger UI will load it asynchronously from this endpoint
ExpressKit supports automatic generation of security requirements in OpenAPI documentation based on the authentication handlers used in your routes.
withSecurityScheme allows you to add security metadata to any authentication handler.bearerAuth: JWT/Bearer token authenticationapiKeyAuth: API key authenticationbasicAuth: Basic authenticationoauth2Auth: OAuth2 authenticationoidcAuth: OpenID Connect authenticationimport {bearerAuth} from 'expresskit';
import jwt from 'jsonwebtoken';
// Add OpenAPI security scheme metadata to your auth handler
const jwtAuthHandler = bearerAuth('myJwtAuth')(function authenticate(req, res, next) {
// Your authentication logic here
next();
});
// Use in routes
const routes = {
'GET /api/protected': {
handler: protectedRouteHandler,
authHandler: jwtAuthHandler,
},
};
const jwtAuthHandler = bearerAuth(
'jwtAuth', // scheme name in OpenAPI docs
['read:users', 'write:users'], // optional scopes
)(authFunction);
const apiKeyHandler = apiKeyAuth(
'apiKeyAuth', // scheme name
'header', // location: 'header', 'query', or 'cookie'
'X-API-Key', // parameter name
['read', 'write'], // optional scopes
)(authFunction);
const basicAuthHandler = basicAuth(
'basicAuth', // scheme name
['read', 'write'], // optional scopes
)(authFunction);
const oauth2Handler = oauth2Auth(
'oauth2Auth', // scheme name
{
implicit: {
authorizationUrl: 'https://example.com/oauth/authorize',
scopes: {
read: 'Read access',
write: 'Write access',
},
},
},
['read', 'write'], // optional scopes for this specific handler
)(authFunction);
const oidcHandler = oidcAuth(
'oidcAuth', // scheme name
'https://example.com/.well-known/openid-configuration',
['profile', 'email'], // optional scopes
)(authFunction);
If you need a custom security scheme, you can use the withSecurityScheme function directly:
import {withSecurityScheme} from 'expresskit';
const customAuthHandler = withSecurityScheme({
name: 'myCustomScheme',
scheme: {
type: 'http',
scheme: 'digest',
description: 'Digest authentication',
},
scopes: ['read', 'write'],
})(authFunction);
Customize the Swagger UI via swaggerUi options or by bringing in theme helpers such as swagger-themes:
import {SwaggerTheme, SwaggerThemeNameEnum} from 'swagger-themes';
const theme = new SwaggerTheme();
const {registerRoutes} = createOpenApiRegistry({
swaggerUi: {
explorer: true,
customCss: theme.getBuffer(SwaggerThemeNameEnum.DARK),
},
});
See src/example/index.ts for a more elaborate setup that combines authentication examples with custom styling.
FAQs
ExpressKit OpenApi Integration
We found that @gravity-ui/expresskit-api demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.

Security News
Socket CEO Feross Aboukhadijeh joins Insecure Agents to discuss CVE remediation and why supply chain attacks require a different security approach.

Security News
Tailwind Labs laid off 75% of its engineering team after revenue dropped 80%, as LLMs redirect traffic away from documentation where developers discover paid products.