# Models
As Strapi is a headless Content Management System (CMS), creating a data structure for the content is one of the most important aspects of using the software. Models define a representation of the data structure.
There are 2 different types of models in Strapi:
- content-types, which can be collection types or single types, depending on how many entries they manage,
- and components that are data structures re-usable in multiple content-types.
If you are just starting out, it is convenient to generate some models with the Content-Type Builder directly in the admin panel. The user interface takes over a lot of validation tasks and showcases all the options available to create the content's data structure. The generated model mappings can then be reviewed at the code level using this documentation.
# Model creation
Content-types and components models are created and stored differently.
# Content-types
Content-types in Strapi can be created:
- with the Content-Type Builder in the admin panel,
- or with Strapi's interactive CLI
strapi generate
command.
The content-types has the following models files:
schema.json
for the model's schema definition. (generated automatically, when creating content-type with either method)lifecycles.js
for lifecycle hooks. This file must be created manually.
These models files are stored in ./src/api/[api-name]/content-types/[content-type-name]/
, and any JavaScript or JSON file found in these folders will be loaded as a content-type's model (see project structure).
# Components
Component models can't be created with CLI tools. Use the Content-Type Builder or create them manually.
Components models are stored in the ./src/components
folder. Every component has to be inside a subfolder, named after the category the component belongs to (see project structure).
# Model schema
The schema.json
file of a model consists of:
- settings, such as the kind of content-type the model represents or the table name in which the data should be stored,
- information, mostly used to display the model in the admin panel and access it through the REST and GraphQL APIs,
- attributes, which describe the data structure of the model,
- and options used to defined specific behaviors on the model.
# Model settings
General settings for the model can be configured with the following parameters:
Parameter | Type | Description |
---|---|---|
tableName | String | Database table name in which the data should be stored |
kind Optional, only for content-types | String | Defines if the content-type is:
|
// ./api/[api-name]/content-types/restaurant/schema.json
{
"kind": "collectionType",
"tableName": "Restaurants_v1",
}
# Model information
The info
key in the model's schema describes information used to display the model in the admin panel and access it through the Content API. It includes the following parameters:
Parameter | Type | Description |
---|---|---|
displayName | String | Default name to use in the admin panel |
singularName | String | Singular form of the collection type name. Used to generate the API routes and databases/tables collection. Should be kebab-case. |
pluralName | String | Plural form of the collection type name. Used to generate the API routes and databases/tables collection. Should be kebab-case. |
description | String | Description of the model |
icon Optional, only for Components | String | FontAwesome (opens new window) (v5) icon name to use for the component's icon in the admin panel |
// ./src/api/[api-name]/content-types/restaurant/schema.json
"info": {
"displayName": "Restaurant",
"singularName": "restaurant",
"pluralName": "restaurants",
"description": ""
},
# Model attributes
The data structure of a model consists of a list of attributes. Each attribute has a type
parameter, which describes its nature and defines the attribute as a simple piece of data or a more complex structure used by Strapi.
Many types of attributes are available:
- scalar types (e.g. strings, dates, numbers, booleans, etc.),
- Strapi-specific types, such as:
media
, for files uploaded through the Media libraryrelation
to describe a relation between content-typescomponent
to define a component (i.e. a data structure usable in multiple content-types)dynamiczone
to define a dynamic zone (i.e. a flexible space based on a list of components)- and the
locale
andlocalizations
types, only used by the Internationalization (i18n) plugin
The type
parameter of an attribute should be one of the following values:
Type categories | Available types |
---|---|
String types |
|
Date types |
|
Number types |
|
Other generic types |
|
Special types unique to Strapi | |
Internationalization (i18n)-related types Can only be used if the i18n plugin is installed |
|
# Validations
Basic validations can be applied to attributes using the following parameters:
Parameter | Type | Description | Default |
---|---|---|---|
required | Boolean | If true , adds a required validator for this property | false |
max | Integer | Checks if the value is greater than or equal to the given maximum | - |
min | Integer | Checks if the value is less than or equal to the given minimum | - |
minLength | Integer | Minimum number of characters for a field input value | - |
maxLength | Integer | Maximum number of characters for a field input value | - |
private | Boolean | If true , the attribute will be removed from the server response.๐ก This is useful to hide sensitive data. | false |
configurable | Boolean | If false , the attribute isn't configurable from the Content-Type Builder plugin. | true |
// ./src/api/[api-name]/content-types/restaurant/schema.json
{
...
"attributes": {
"title": {
"type": "string",
"minLength": 3,
"maxLength": 99,
"unique": true
},
"description": {
"default": "My description",
"type": "text",
"required": true
},
"slug": {
"type": "uid",
"targetField": "title"
}
...
}
}
# uid
type
The uid
type is used to automatically prefill the field value in the admin panel with a unique identifier (UID) (e.g. slugs for articles) based on 2 optional parameters:
targetField
(string): If used, the value of the field defined as a target is used to auto-generate the UID.options
(string): If used, the UID is generated based on a set of options passed to the underlyinguid
generator (opens new window). The resultinguid
must match the following regular expression pattern:/^[A-Za-z0-9-_.~]*$
.
# Relations
Relations link content-types together. Relations are explicitly defined in the attributes of a model with type: 'relation'
and accept the following additional parameters:
Parameter | Description |
---|---|
relation | The type of relation among these values:
manyToMany |
target | Accepts a string value as the name of the target content-type |
mappedBy and inversedBy Optional | In bidirectional relations, the owning side declares the inversedBy key while the inversed side declares the mappedBy key |
# Components
Component fields create a relation between a content-type and a component structure. Components are explicitly defined in the attributes of a model with type: 'component'
and accept the following additional parameters:
Parameter | Type | Description |
---|---|---|
repeatable | Boolean | Could be true or false depending on whether the component is repeatable or not |
component | String | Define the corresponding component, following this format:<category>.<componentName> |
// ./src/api/[apiName]/restaurant/content-types/schema.json
{
"attributes": {
"openinghours": {
"type": "component",
"repeatable": true,
"component": "restaurant.openinghours"
}
}
}
# Dynamic zones
Dynamic zones create a flexible space in which to compose content, based on a mixed list of components.
Dynamic zones are explicitly defined in the attributes of a model with type: 'dynamiczone'
. They also accepts a components
array, where each component should be named following this format: <category>.<componentName>
.
// ./src/api/[api-name]/content-types/article/schema.json
{
"attributes": {
"body": {
"type": "dynamiczone",
"components": ["article.slider", "article.content"]
}
}
}
# Model options
The options
key is used to define specific behaviors and accepts the following parameter:
Parameter | Type | Description |
---|---|---|
privateAttributes | Array of strings | Allows treating a set of attributes as private, even if they're not actually defined as attributes in the model. It could be used to remove them from API responses timestamps. The set of privateAttributes defined in the model are merged with the privateAttributes defined in the global Strapi configuration. |
populateCreatorFields | Boolean | Toggles including the created_by and updated_by fields in the API response.Default value: false |
draftAndPublish | Boolean | Enables the draft and publish feature. Default value: false |
// ./src/api/[api-name]/content-types/restaurant/schema.json
{
"options": {
"privateAttributes": ["id", "created_at"],
"populateCreatorFields": true,
"draftAndPublish": false
}
}
# Lifecycle hooks
Lifecycle hooks are functions that get triggered when Strapi queries are called. They are triggered automatically when managing content through the administration panel or when developing custom code using queries
ยท
Lifecycle hooks can be customized declaratively or programmatically.
โ CAUTION
Lifecycles hooks are not triggered when using directly the knex (opens new window) library instead of Strapi functions.
# Available lifecycle events
The following lifecycle events are available:
beforeCreate
beforeCreateMany
afterCreate
afterCreateMany
beforeUpdate
beforeUpdateMany
afterUpdate
afterUpdateMany
beforeDelete
beforeDeleteMany
afterDelete
afterDeleteMany
beforeCount
afterCount
beforeFindOne
afterFindOne
beforeFindMany
afterFindMany
# Hook event
object
Lifecycle hooks are functions that take an event
parameter, an object with the following keys:
Key | Type | Description |
---|---|---|
action | String | Lifecycle event that has been triggered (see list) |
model | Object | Model object |
em | EntityManagerObject | EntityManager |
params | Object | Accepts the following parameters:
|
result | Object | Optional, only available with afterXXX eventsContains the result of the action. |
state | Object | Query state, can be used to share state between beforeXXX and afterXXX events of a query. |
# Declarative and programmatic usage
To configure a content-type lifecycle hook, create a lifecycles.js
file in the ./api/[api-name]/content-types/[content-type-name]/
folder.
Each event listener is called sequentially. They can be synchronous or asynchronous.
// ./src/api/[api-name]/content-types/restaurant/lifecycles.js
module.exports = {
beforeCreate(event: Event) {
const { data, where, select, populate } = event.params;
// let's do a 20% discount everytime
event.params.data.price = event.params.data.price * 0.8;
},
afterCreate(event: Event) {
const { result, params } = event;
// do something to the result;
},
};
Using the database layer API, it's also possible to register a subscriber and listen to events programmatically:
// ./src/api/[api-name]/content-types/restaurant/lifecycles.js
// registering a subscriber
strapi.db.lifecycles.subscribe({
models: [], // optional;
beforeCreate(event: Event) {
const { data, where, select, populate } = event.params;
event.state = 'doStuffAfterWards';
},
afterCreate(event: Event) {
if (event.state === 'doStuffAfterWards') {
}
const { result, params } = event;
// do something to the result
},
});
// generic subscribe for generic handling
strapi.db.lifecycles.subscribe((event) => {
if (event.action === 'beforeCreate') {
// do something
}
});