Server API for plugins
A Strapi plugin can interact with both the back end and the front end of a Strapi application. The Server API is about the back-end part, i.e. how the plugin interacts with the server part of a Strapi application.
You have created a Strapi plugin.
The Server API includes:
- an entry file which export the required interface,
- lifecycle functions,
- a configuration API,
- the ability to add cron jobs,
- and the ability to customize all elements of the back-end server.
Once you have declared and exported the plugin interface, you will be able to use the plugin interface.
The whole code for the server part of your plugin could live in the /server/src/index.ts|js
file. However, it's recommended to split the code into different folders, just like the structure created by the Plugin SDK.
Entry file
The /src/server/index.js
file at the root of the plugin folder exports the required interface, with the following parameters available:
Parameter type | Available parameters |
---|---|
Lifecycle functions | |
Configuration |
|
Backend customizations |
Lifecycle functions
register()
This function is called to load the plugin, before the application is bootstrapped, in order to register permissions, the server part of custom fields, or database migrations.
Type: Function
Example:
- JavaScript
- TypeScript
'use strict';
const register = ({ strapi }) => {
// execute some register code
};
module.exports = register;
import type { Core } from '@strapi/strapi';
const register = ({ strapi }: { strapi: Core.Strapi }) => {
// execute some register code
};
export default register;
bootstrap()
The bootstrap function is called right after the plugin has registered.
Type: Function
Example:
- JavaScript
- TypeScript
'use strict';
const bootstrap = ({ strapi }) => {
// execute some bootstrap code
};
module.exports = bootstrap;
import type { Core } from '@strapi/strapi';
const bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {
// execute some bootstrap code
};
export default bootstrap;
destroy()
The destroy lifecycle function is called to cleanup the plugin (close connections, remove listeners, etc.) when the Strapi instance is destroyed.
Type: Function
Example:
- JavaScript
- TypeScript
'use strict';
const destroy = ({ strapi }) => {
// execute some destroy code
};
module.exports = destroy;
import type { Core } from '@strapi/strapi';
const destroy = ({ strapi }: { strapi: Core.Strapi }) => {
// destroy phase
};
export default destroy;
Configuration
config
stores the default plugin configuration. It loads and validates the configuration inputted from the user within the ./config/plugins.js
configuration file.
Type: Object
Parameter | Type | Description |
---|---|---|
default | Object, or Function that returns an Object | Default plugin configuration, merged with the user configuration |
validator | Function |
|
Example:
- JavaScript
- TypeScript
module.exports = {
default: ({ env }) => ({ optionA: true }),
validator: (config) => {
if (typeof config.optionA !== 'boolean') {
throw new Error('optionA has to be a boolean');
}
},
};
export default {
default: ({ env }) => ({ optionA: true }),
validator: (config) => {
if (typeof config.optionA !== 'boolean') {
throw new Error('optionA has to be a boolean');
}
},
};
Once defined, the configuration can be accessed:
- with
strapi.plugin('plugin-name').config('some-key')
for a specific configuration property, - or with
strapi.config.get('plugin.plugin-name')
for the whole configuration object.
Run yarn strapi console
or npm run strapi console
to access the strapi object in a live console.
Backend customization
All elements of the back-end server of Strapi can be customized through a plugin using the Server API.
To better understand this section, ensure you have read through the back-end customization documentation of a Strapi application.
Content-types
An object with the content-types the plugin provides.
Type: Object
Content-Types keys in the contentTypes
object should re-use the singularName
defined in the info
key of the schema.
Example:
- JavaScript
- TypeScript
'use strict';
const contentTypeA = require('./content-type-a');
const contentTypeB = require('./content-type-b');
module.exports = {
'content-type-a': { schema: contentTypeA }, // should re-use the singularName of the content-type
'content-type-b': { schema: contentTypeB },
};
module.exports = {
kind: 'collectionType',
collectionName: 'content-type',
info: {
singularName: 'content-type-a', // kebab-case mandatory
pluralName: 'content-type-as', // kebab-case mandatory
displayName: 'Content Type A',
description: 'A regular content-type',
},
options: {
draftAndPublish: true,
},
pluginOptions: {
'content-manager': {
visible: false,
},
'content-type-builder': {
visible: false,
}
},
attributes: {
name: {
type: 'string',
min: 1,
max: 50,
configurable: false,
},
}
};
const contentTypeA = require('./content-type-a');
const contentTypeB = require('./content-type-b');
module.exports = {
'content-type-a': { schema: contentTypeA }, // should re-use the singularName of the content-type
'content-type-b': { schema: contentTypeB },
};
export default {
kind: 'collectionType',
collectionName: 'content-type',
info: {
singularName: 'content-type-a', // kebab-case mandatory
pluralName: 'content-type-as', // kebab-case mandatory
displayName: 'Content Type A',
description: 'A regular content-type',
},
options: {
draftAndPublish: true,
},
pluginOptions: {
'content-manager': {
visible: false,
},
'content-type-builder': {
visible: false,
}
},
attributes: {
name: {
type: 'string',
min: 1,
max: 50,
configurable: false,
},
}
};
Routes
An array of routes configuration.
Type: Object[]
Examples:
- Content API routes only
- Content API and admin routes
- JavaScript
- TypeScript
const routes = require('./routes');
module.exports = () => ({
routes,
type: 'content-api', // can also be 'admin' depending on the type of route
});
module.exports = [
{
method: 'GET',
path: '/model',
handler: 'controllerName.action',
config: {
policies: ['policyName'],
},
},
];
const routes = require('./routes');
export default {
routes,
type: 'content-api', // can also be 'admin' depending on the type of route
};
export default [
{
method: 'GET',
path: '/model',
handler: 'controllerName.action',
config: {
policies: ['policyName'],
},
},
];
It is also possible to combine both admin and Content API routes if you need different policies on these:
- JavaScript
- TypeScript
module.exports = {
admin: require('./admin'),
'content-api': require('./content-api'),
};
module.exports = {
type: 'admin',
routes: [{
method: 'GET',
path: '/model',
handler: 'controllerName.action',
config: {
policies: ['policyName'],
},
}],
};
module.exports = {
type: 'content-api',
routes: [{
method: 'GET',
path: '/model',
handler: 'controllerName.action',
config: {
policies: ['differentPolicyName'],
},
}],
};
export default {
admin: require('./admin'),
'content-api': require('./content-api'),
};
export default {
type: 'admin',
routes: [{
method: 'GET',
path: '/model',
handler: 'controllerName.action',
config: {
policies: ['policyName'],
},
}],
};
export default {
type: 'content-api',
routes: [{
method: 'GET',
path: '/model',
handler: 'controllerName.action',
config: {
policies: ['differentPolicyName'],
},
}],
};
Controllers
An object with the controllers the plugin provides.
Type: Object
Example:
- JavaScript
- TypeScript
//…
const controllers = require('./controllers');
//…
module.exports = () => ({
//…
controllers,
//…
});
const controllerA = require('./controller-a');
const controllerB = require('./controller-b');
module.exports = {
controllerA,
controllerB,
};
'use strict';
const controllerA = ({ strapi }) => ({
index(ctx) {
ctx.body = strapi
.plugin('my-strapi-plugin')
// the name of the service file & the method.
.service('service')
.getWelcomeMessage();
},
});
module.exports = controllerA;
import controllers from './controllers';
module.exports = () => ({
controllers,
});
import controllerA from './controller-a';
import controllerB from './controller-b';
export default {
controllerA,
controllerB,
};
import type { Core } from '@strapi/strapi';
const controllerA = ({ strapi }: { strapi: Core.Strapi }) => ({
index(ctx) {
ctx.body = strapi
.plugin('my-strapi-plugin')
// the name of the service file & the method.
.service('service')
.getWelcomeMessage();
},
});
export default controllerA;
Services
An object with the services the plugin provides.
Services should be functions taking strapi
as a parameter.
Type: Object
Example:
- JavaScript
- TypeScript
// …
const services = require('./services');
// …
module.exports = () => ({
// …
services,
// …
});
const serviceA = require('./service-a');
const serviceB = require('./service-b');
module.exports = {
serviceA,
serviceB,
};
'use strict';
const service = ({ strapi }) => ({
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
});
module.exports = service;
// …
import services from './services';
// …
export default {
// …
services,
// …
};
import serviceA from './service-a';
import serviceB from './service-b';
export default {
serviceA,
serviceB,
};
import type { Core } from '@strapi/strapi';
const serviceA = ({ strapi }: { strapi: Core.Strapi }) => ({
getWelcomeMessage() {
return 'Welcome to Strapi 🚀';
},
});
export default serviceA;
Policies
An object with the policies the plugin provides.
Type: Object
Example:
- JavaScript
- TypeScript
"use strict";
//…
const policies = require('./policies');
//…
module.exports = {
//…
policies,
//…
};
const policyA = require('./policy-a');
const policyB = require('./policy-b');
module.exports = {
policyA,
policyB,
};
module.exports = (policyContext, config, { strapi }) => {
if (ctx.state.user && ctx.state.user.isActive) {
return true;
}
return false;
};
//…
import policies from './policies';
//…
module.exports = {
//…
policies,
//…
};
import policyA from './policy-a';
import policyB from './policy-b';
export default {
policyA,
policyB,
};
export default (policyContext, config, { strapi }) => {
if (ctx.state.user && ctx.state.user.isActive) {
return true;
}
return false;
};
Middlewares
An object with the middlewares the plugin provides.
Type: Object
Example:
- JavaScript
- TypeScript
/**
* The your-middleware.js file
* declares a basic middleware function and exports it.
*/
'use strict';
module.exports = async (ctx, next) => {
console.log("your custom logic")
await next();
}
/**
* The middleware function previously created
* is imported from its file and
* exported by the middlewares index.
*/
'use strict';
const yourMiddleware = require('./your-middleware');
module.exports = {
yourMiddleware
};
/**
* The middleware is called from
* the plugin's register lifecycle function.
*/
'use strict';
const middlewares = require('./middlewares');
module.exports = ({ strapi }) => {
strapi.server.use(middlewares.yourMiddleware);
};
/**
* The your-middleware.js file
* declares a basic middleware function and exports it.
*/
const middleware = async (ctx, next) => {
console.log("your custom logic")
await next();
}
export default middleware;
/**
* The middleware function previously created
* is imported from its file and
* exported by the middlewares index.
*/
import yourMiddleware from 'your-middleware';
export default {
yourMiddleware
};
/**
* The middleware is called from
* the plugin's register lifecycle function.
*/
import type { Core } from '@strapi/strapi';
import middlewares from './middlewares';
export default ({ strapi }: { strapi: Core.Strapi }) => {
strapi.server.use(middlewares.yourMiddleware);
};
Usage
Once a plugin is exported and loaded into Strapi, its features are accessible in the code through getters. The Strapi instance (strapi
) exposes both top-level getters and global getters:
- top-level getters imply chaining functions
(e.g.,strapi.plugin('the-plugin-name').controller('the-controller-name'
), - global getters are syntactic sugar that allows direct access using a feature's uid
(e.g.,strapi.controller('plugin::plugin-name.controller-name')
).
// Access an API or a plugin controller using a top-level getter
strapi.api['api-name'].controller('controller-name')
strapi.plugin('plugin-name').controller('controller-name')
// Access an API or a plugin controller using a global getter
strapi.controller('api::api-name.controller-name')
strapi.controller('plugin::plugin-name.controller-name')
Top-level getter syntax examples
strapi.plugin('plugin-name').config
strapi.plugin('plugin-name').routes
strapi.plugin('plugin-name').controller('controller-name')
strapi.plugin('plugin-name').service('service-name')
strapi.plugin('plugin-name').contentType('content-type-name')
strapi.plugin('plugin-name').policy('policy-name')
strapi.plugin('plugin-name').middleware('middleware-name')
Global getter syntax examples
strapi.controller('plugin::plugin-name.controller-name');
strapi.service('plugin::plugin-name.service-name');
strapi.contentType('plugin::plugin-name.content-type-name');
strapi.policy('plugin::plugin-name.policy-name');
strapi.middleware('plugin::plugin-name.middleware-name');
To interact with the content-types, use the Document Service API.