mirror of
https://github.com/strapi/strapi.git
synced 2025-12-04 02:51:26 +00:00
Merge branch 'master' into fix/forgot-password-url
This commit is contained in:
commit
c69e3fd042
@ -100,35 +100,41 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
collapsable: true,
|
||||
title: '💡 Guides',
|
||||
title: '💡 Concepts',
|
||||
children: [
|
||||
'/3.0.0-beta.x/concepts/file-structure',
|
||||
'/3.0.0-beta.x/concepts/configurations',
|
||||
'/3.0.0-beta.x/concepts/requests-responses',
|
||||
'/3.0.0-beta.x/concepts/customization',
|
||||
'/3.0.0-beta.x/concepts/routing',
|
||||
'/3.0.0-beta.x/concepts/controllers',
|
||||
'/3.0.0-beta.x/concepts/models',
|
||||
'/3.0.0-beta.x/concepts/services',
|
||||
'/3.0.0-beta.x/concepts/queries',
|
||||
'/3.0.0-beta.x/concepts/parameters',
|
||||
'/3.0.0-beta.x/concepts/policies',
|
||||
'/3.0.0-beta.x/concepts/public-assets',
|
||||
'/3.0.0-beta.x/concepts/hooks',
|
||||
'/3.0.0-beta.x/concepts/middlewares',
|
||||
'/3.0.0-beta.x/concepts/logging',
|
||||
'/3.0.0-beta.x/concepts/plugins',
|
||||
],
|
||||
},
|
||||
{
|
||||
collapsable: true,
|
||||
title: '📚 Guides',
|
||||
children: [
|
||||
'/3.0.0-beta.x/concepts/concepts',
|
||||
'/3.0.0-beta.x/configurations/configurations',
|
||||
'/3.0.0-beta.x/guides/controllers',
|
||||
'/3.0.0-beta.x/guides/databases',
|
||||
'/3.0.0-beta.x/guides/deployment',
|
||||
'/3.0.0-beta.x/guides/parameters',
|
||||
'/3.0.0-beta.x/guides/i18n',
|
||||
'/3.0.0-beta.x/guides/models',
|
||||
'/3.0.0-beta.x/guides/policies',
|
||||
'/3.0.0-beta.x/guides/public-assets',
|
||||
'/3.0.0-beta.x/guides/requests',
|
||||
'/3.0.0-beta.x/guides/responses',
|
||||
'/3.0.0-beta.x/guides/routing',
|
||||
'/3.0.0-beta.x/guides/services',
|
||||
'/3.0.0-beta.x/guides/queries',
|
||||
'/3.0.0-beta.x/guides/webhooks',
|
||||
],
|
||||
},
|
||||
{
|
||||
collapsable: true,
|
||||
title: '⚙️️ Advanced',
|
||||
title: '⚙️️ Admin panel',
|
||||
children: [
|
||||
'/3.0.0-beta.x/advanced/customize-admin',
|
||||
'/3.0.0-beta.x/advanced/hooks',
|
||||
'/3.0.0-beta.x/advanced/logging',
|
||||
'/3.0.0-beta.x/advanced/middlewares',
|
||||
'/3.0.0-beta.x/advanced/usage-information',
|
||||
'/3.0.0-beta.x/admin-panel/customization',
|
||||
'/3.0.0-beta.x/admin-panel/deploy',
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -162,7 +168,10 @@ module.exports = {
|
||||
{
|
||||
collapsable: true,
|
||||
title: '🏗 Global strapi',
|
||||
children: ['/3.0.0-beta.x/global-strapi/reference'],
|
||||
children: [
|
||||
'/3.0.0-beta.x/global-strapi/api-reference',
|
||||
'/3.0.0-beta.x/global-strapi/usage-information',
|
||||
],
|
||||
},
|
||||
{
|
||||
collapsable: false,
|
||||
|
||||
@ -1,10 +1,4 @@
|
||||
# Admin panel
|
||||
|
||||
One of Strapi's main feature is its fully extendable and customizable admin panel. This section explains how the admin panel section is structured and how to customize it.
|
||||
|
||||
See the [Contributing Guide](https://github.com/strapi/strapi/blob/master/CONTRIBUTING.md) for information on how to contribute to Strapi's admin interface.
|
||||
|
||||
## Customization
|
||||
# Customization
|
||||
|
||||
The administration panel can be customized according to your needs, so you can make it reflects your identity.
|
||||
|
||||
@ -12,7 +6,7 @@ The administration panel can be customized according to your needs, so you can m
|
||||
To apply your changes you need to [rebuild](#build) your admin panel
|
||||
:::
|
||||
|
||||
### Change access URL
|
||||
## Change access URL
|
||||
|
||||
By default, the administration panel is exposed via [http://localhost:1337/admin](http://localhost:1337/admin). However, for security reasons, you can easily update this path.
|
||||
|
||||
@ -33,9 +27,7 @@ By default, the administration panel is exposed via [http://localhost:1337/admin
|
||||
|
||||
The panel will be available through [http://localhost:1337/dashboard](http://localhost:1337/dashboard) with the configurations above.
|
||||
|
||||
---
|
||||
|
||||
### Development mode
|
||||
## Development mode
|
||||
|
||||
To enable the front-end development mode you need to start your application using the `--watch-admin` flag.
|
||||
|
||||
@ -46,7 +38,7 @@ strapi develop --watch-admin
|
||||
|
||||
With this option you can do the following:
|
||||
|
||||
#### Customize the `strapi-admin` package
|
||||
### Customize the `strapi-admin` package
|
||||
|
||||
All files added in `my-app/admin/src/` will either be replaced or added
|
||||
|
||||
@ -116,7 +108,7 @@ export { languages, translationMessages };
|
||||
With this modification only English and French will be available in your admin
|
||||
:::
|
||||
|
||||
#### Customize a plugin
|
||||
### Customize a plugin
|
||||
|
||||
Similarly to the back-end override system any file added in `my-app/extensions/<plugin-name>/admin/` will be copied and used instead of the original one (use with care).
|
||||
|
||||
@ -146,8 +138,6 @@ const WysiwygWithErrors = props => <MyNewWYSIWYG {...props} />;
|
||||
export default WysiwygWithErrors;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Styles
|
||||
|
||||
The AdminUI package source can be easily found in `./node_modules/strapi-admin/src/`.
|
||||
@ -162,8 +152,6 @@ To apply your changes you need to rebuild your admin panel
|
||||
npm run build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Logo
|
||||
|
||||
To change the top-left displayed admin panel's logo, add your custom image at `./admin/src/assets/images/logo-strapi.png`.
|
||||
@ -245,100 +233,3 @@ NODE_ENV=production strapi build
|
||||
::::
|
||||
|
||||
This will replace the folder's content located at `./build`. Visit [http://localhost:1337/admin](http://localhost:1337/admin) to make sure your updates have been taken into account.
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
The administration is nothing more than a React front-end application calling an API. The front-end and the back-end are independent and can be deployed on different servers which brings us to different scenarios:
|
||||
|
||||
1. Deploy the entire project on the same server.
|
||||
2. Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
|
||||
|
||||
Let's dive into the build configurations for each case.
|
||||
|
||||
#### Deploy the entire project on the same server.
|
||||
|
||||
You don't need to touch anything in your configuration file. This is the default behavior and the build configurations will be automatically set. The server will start on the defined port and the administration panel will be accessible through `http://yourdomain.com:1337/dashboard`.
|
||||
|
||||
You might want to change the path to access to the administration panel. Here the required configurations to change the path:
|
||||
|
||||
**Path —** `./config/environment/**/server.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 1337,
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"path": "/dashboard" // We change the path to access to the admin (highly recommended for security reasons).
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**You have to rebuild the administration panel to make this work.** [Build instructions](#build).
|
||||
|
||||
#### Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
|
||||
|
||||
It's very common to deploy the front-end and the back-end on different servers. Here the required configurations to handle this case:
|
||||
|
||||
**Path —** `./config/environment/**/server.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 1337,
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"path": "/", // Note: The administration will be accessible from the root of the domain (ex: http//yourfrontend.com/)
|
||||
"build": {
|
||||
"backend": "http://yourbackend.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The administration URL will be `http://yourfrontend.com` and every request from the panel will hit the backend at `http://yourbackend.com`.
|
||||
|
||||
#### Deploy the administration panel and the plugins on another server than the API
|
||||
|
||||
In this case, we suppose that you decided to put your administration panel on a different server than the API.
|
||||
|
||||
**Path —** `./config/environment/**/server.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 1337,
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"path": "/dashboard",
|
||||
"build": {
|
||||
"backend": "http://yourbackend.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The administration URL will be `http://yourfrontend.com/dashboard` and every request from the panel will hit the backend at `http://yourbackend.com`.
|
||||
|
||||
The generated `index.html` will look like this:
|
||||
|
||||
**Path —** `./build/index.html`.
|
||||
|
||||
```html
|
||||
<html lang="en">
|
||||
<head></head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="/dashboard/runtime~main.js"></script>
|
||||
<script type="text/javascript" src="/dashboard/main.chunk.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
94
docs/3.0.0-beta.x/admin-panel/deploy.md
Normal file
94
docs/3.0.0-beta.x/admin-panel/deploy.md
Normal file
@ -0,0 +1,94 @@
|
||||
# Deployment
|
||||
|
||||
The administration is nothing more than a React front-end application calling an API. The front-end and the back-end are independent and can be deployed on different servers which brings us to different scenarios:
|
||||
|
||||
1. Deploy the entire project on the same server.
|
||||
2. Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
|
||||
|
||||
Let's dive into the build configurations for each case.
|
||||
|
||||
## Deploy the entire project on the same server.
|
||||
|
||||
You don't need to touch anything in your configuration file. This is the default behavior and the build configurations will be automatically set. The server will start on the defined port and the administration panel will be accessible through `http://yourdomain.com:1337/dashboard`.
|
||||
|
||||
You might want to change the path to access to the administration panel. Here the required configurations to change the path:
|
||||
|
||||
**Path —** `./config/environment/**/server.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 1337,
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"path": "/dashboard" // We change the path to access to the admin (highly recommended for security reasons).
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**You have to rebuild the administration panel to make this work.** [Build instructions](#build).
|
||||
|
||||
## Deploy the administration panel on another server (AWS S3, Azure, etc) than the API.
|
||||
|
||||
It's very common to deploy the front-end and the back-end on different servers. Here the required configurations to handle this case:
|
||||
|
||||
**Path —** `./config/environment/**/server.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 1337,
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"path": "/", // Note: The administration will be accessible from the root of the domain (ex: http//yourfrontend.com/)
|
||||
"build": {
|
||||
"backend": "http://yourbackend.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The administration URL will be `http://yourfrontend.com` and every request from the panel will hit the backend at `http://yourbackend.com`.
|
||||
|
||||
## Deploy the administration panel and the plugins on another server than the API
|
||||
|
||||
In this case, we suppose that you decided to put your administration panel on a different server than the API.
|
||||
|
||||
**Path —** `./config/environment/**/server.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": 1337,
|
||||
"cron": {
|
||||
"enabled": false
|
||||
},
|
||||
"admin": {
|
||||
"path": "/dashboard",
|
||||
"build": {
|
||||
"backend": "http://yourbackend.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The administration URL will be `http://yourfrontend.com/dashboard` and every request from the panel will hit the backend at `http://yourbackend.com`.
|
||||
|
||||
The generated `index.html` will look like this:
|
||||
|
||||
**Path —** `./build/index.html`.
|
||||
|
||||
```html
|
||||
<html lang="en">
|
||||
<head></head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="text/javascript" src="/dashboard/runtime~main.js"></script>
|
||||
<script type="text/javascript" src="/dashboard/main.chunk.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@ -1,352 +0,0 @@
|
||||
# Concepts
|
||||
|
||||
- Table of contents
|
||||
- [Files structure](#files-structure)
|
||||
- [Controllers](#controllers)
|
||||
- [Parameters](#parameters)
|
||||
- [Models](#models)
|
||||
- [Attributes](#attributes)
|
||||
- [Relations](#relations)
|
||||
- [Many-to-many](#many-to-many)
|
||||
- [One-to-many](#one-to-many)
|
||||
- [One-to-one](#one-to-one)
|
||||
- [One-way](#one-way)
|
||||
- [Lifecycle callbacks](#lifecycle-callbacks)
|
||||
- [Internationalization](#internationalization-and-localization)
|
||||
- [Plugin](#plugin)
|
||||
- [Extensions](#extensions)
|
||||
- [Policies](#policies)
|
||||
- [Global policies](#global-policies)
|
||||
- [Scoped policies](#scoped-policies)
|
||||
- [Plugin policies](#plugin-policies)
|
||||
- [Public assets](#public-assets)
|
||||
- [Requests](#requests)
|
||||
- [Responses](#responses)
|
||||
- [Routing](#routing)
|
||||
- [Services](#services)
|
||||
- [Queries](#queries)
|
||||
|
||||
---
|
||||
|
||||
## Files structure
|
||||
|
||||
By default, your project's structure will look like this:
|
||||
|
||||
- `/api`: contains the business logic of your project split in sub-folder per API.
|
||||
- `**`
|
||||
- `/config`: contains the API's configurations ([`routes`](#routing), [`policies`](#policies), etc).
|
||||
- [`/controllers`](#controllers): contains the API's custom controllers.
|
||||
- [`/models`](#models): contains the API's models.
|
||||
- [`/services`](#services): contains the API's custom services.
|
||||
- `/node_modules`: contains the npm's packages used by the project.
|
||||
- [`/config`](../configurations/configurations.md)
|
||||
- [`/environments`](../configurations/configurations.md#environments): contains the project's configurations per environment.
|
||||
- `/**`
|
||||
- `/development`
|
||||
- [`custom.json`](../configurations/configurations.md#custom): contains the custom configurations for this environment.
|
||||
- [`database.json`](../configurations/configurations.md#database): contains the database connections for this environment.
|
||||
- [`request.json`](../configurations/configurations.md#request): contains the request settings for this environment.
|
||||
- [`response.json`](../configurations/configurations.md#response): contains the response settings for this environment.
|
||||
- [`server.json`](../configurations/configurations.md#server): contains the server settings for this environment.
|
||||
- `/production`
|
||||
- `/staging`
|
||||
- [`/functions`](../configurations/configurations.html#functions): contains lifecycle or generic functions of the project.
|
||||
- [`/locales`](../configurations/configurations.html#locales): contains the translation files used by the built-in i18n feature.
|
||||
- [`application.json`](../configurations/configurations.html#application): contains the general configurations of the project.
|
||||
- [`custom.json`](../configurations/configurations.html#custom): contains the custom configurations of the project.
|
||||
- [`hook.json`](../configurations/configurations.html#hook): contains the hook settings of the project.
|
||||
- [`language.json`](../configurations/configurations.html#language): contains the language settings of the project.
|
||||
- [`middleware.json`](../configurations/configurations.html#middleware): contains the middleware settings of the project.
|
||||
- [`/hooks`](../advanced/hooks.html): contains the custom hooks of the project.
|
||||
- [`/middlewares`](../advanced/middlewares.html): contains the custom middlewares of the project.
|
||||
- [`/admin`](../advanced/customize-admin.md): contains your admin customization files.
|
||||
- [`/extensions`](#extensions): contains the files to extend installed plugins.
|
||||
- [`/plugins`](#plugin): contains your local plugins.
|
||||
- [`/public`](#public-assets): contains the file accessible to the outside world.
|
||||
- `/build`: contains your admin panel UI build.
|
||||
- `/.cache`: contains files used to build your admin panel.
|
||||
|
||||
::: note
|
||||
Inside the `/config` folder, every folder will be parsed and injected into the global object `strapi.config`. Let's say, you added a folder named `credentials` with two files `stripe.json` and `paypal.json` into it. The content of these files will be accessible through `strapi.config.credentials.stripe` and `strapi.config.credentials.paypal`.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Controllers
|
||||
|
||||
Controllers are JavaScript files which contain a set of methods called **actions** reached by the client according to the requested route. It means that every time a client requests the route, the action performs the business logic coded and sends back the response. They represent the _C_ in the _MVC_ pattern. In most cases, the controllers will contain the bulk of a project's business logic.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// GET /hello
|
||||
index: async ctx => {
|
||||
ctx.send('Hello World!');
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
In this example, any time a web browser is pointed to the `/hello` URL on your app, the page will display the text: `Hello World!`.
|
||||
|
||||
### Where are the controllers defined?
|
||||
|
||||
The controllers are defined in each `./api/**/controllers/` folders. Every JavaScript file put in these folders will be loaded as a controller. They are also available through the `strapi.controllers` and `strapi.api.**.controllers` global variables. By convention, controllers' names should be Pascal-cased, so that every word in the file (include the first one) is capitalized `User.js`, `LegalEntity.js`.
|
||||
|
||||
::: note
|
||||
Please refer to the [controllers' guide](../guides/controllers.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Parameters
|
||||
|
||||
Parameters are a handy way to request data according to generic parameters. It makes filtering, sorting and paginating easy and reusable (eg. `GET /users?_limit=30&name=John`).
|
||||
|
||||
::: note
|
||||
Please refer to the [parameters' guide](../content-api/parameters.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Models
|
||||
|
||||
Models are a representation of the database's structure and lifecycle. They are split into two separate files. A JavaScript file that contains the lifecycle callbacks, and a JSON one that represents the data stored in the database and their format. The models also allow you to define the relationships between them.
|
||||
|
||||
**Path —** `./api/user/models/User.js`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
beforeSave: next => {
|
||||
// Use `this` to get your current object
|
||||
next();
|
||||
},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
afterSave: (doc, next) => {
|
||||
next();
|
||||
},
|
||||
|
||||
// ... and more
|
||||
};
|
||||
```
|
||||
|
||||
**Path —** `./api/user/models/User.settings.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"connection": "default",
|
||||
"info": {
|
||||
"name": "user",
|
||||
"description": "This represents the User Model"
|
||||
},
|
||||
"attributes": {
|
||||
"firstname": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastname": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, there is a `User` model which contains two attributes `firstname` and `lastname`.
|
||||
|
||||
### Where are the models defined?
|
||||
|
||||
The models are defined in each `./api/**/models/` folder. Every JavaScript or JSON file in these folders will be loaded as a model. They are also available through the `strapi.models` and `strapi.api.**.models` global variables. Usable everywhere in the project, they contain the ORM model object that they are refer to. By convention, models' names should be written in lowercase.
|
||||
|
||||
### Attributes
|
||||
|
||||
A model must contain a list of attributes, and each of these attributes must have a type.
|
||||
|
||||
::: note
|
||||
Please refer to the [models' guide for more information about the attributes](../guides/models.md#define-the-attributes).
|
||||
:::
|
||||
|
||||
### Relations
|
||||
|
||||
#### Many-to-many
|
||||
|
||||
Many-to-many associations allow to link an entry to many entries.
|
||||
|
||||
::: note
|
||||
Please refer to the [many-to-many guide](../guides/models.md#many-to-many)
|
||||
:::
|
||||
|
||||
#### One-to-many
|
||||
|
||||
One-way relationships are useful to link an entry to another.
|
||||
|
||||
::: note
|
||||
Please refer to the [one-to-many guide](../guides/models.md#one-to-many)
|
||||
:::
|
||||
|
||||
#### One-to-one
|
||||
|
||||
One-way relationships are useful to link an entry to another.
|
||||
|
||||
::: note
|
||||
Please refer to the [one-to-one guide](../guides/models.md#one-to-one).
|
||||
:::
|
||||
|
||||
#### One-way
|
||||
|
||||
One-way relationships are useful to link an entry to another. However, only one of the models can be queried with its populated items.
|
||||
|
||||
::: note
|
||||
Please refer to the [one-way guide](../guides/models.md#one-way).
|
||||
:::
|
||||
|
||||
### Lifecycle callbacks
|
||||
|
||||
Lifecycle callbacks are functions triggered at specific moments of the queries.
|
||||
|
||||
::: note
|
||||
Please refer to the [lifecycle callbacks guide](../guides/models.md#lifecycle-callbacks).
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Internationalization and localization
|
||||
|
||||
Internationalization and localization (i18n) allows to adapt the project to different languages and serve the right content to the users. This feature is deeply integrated into the Strapi's core. It will detect the user language preference (locale) and translate the requested content using the translation files.
|
||||
|
||||
::: note
|
||||
Please refer to the [internationalization's guide](../guides/i18n.md).
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Plugin
|
||||
|
||||
A plugin is like a small independent sub-application. It has its own business logic with dedicated models, controllers, services, middlewares or hooks. It can also have it's own UI integrated in the admin panel.
|
||||
|
||||
::: note
|
||||
Please refer to the [plugins documentation](../plugin-development/quick-start.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Extensions
|
||||
|
||||
In strapi you can install plugins in your `node_modules`. This allows for easy updates and respect best practices. To customize those installed plugins you can work in the `/extensions` directory. It contains all the plugins' customizable files.
|
||||
|
||||
Certain plugins will create files in these folders so you can then modify them. You can also create certain files manually to add some custom configuration for example.
|
||||
|
||||
Depending on the plugins you will find extension documentation directly in the plugin's documentation.
|
||||
|
||||
Extensions folder structure:
|
||||
|
||||
- `extensions/`
|
||||
- `**`: Plugin Id
|
||||
- `config`: You can extend a plugin's configuration by add a settings.json file with your custom configuration
|
||||
- `models`: Contains the plugin's models that you have overwritten (e.g: When you add a relation to the User model)
|
||||
- `controllers`: You can extend the plugin's controllers by create controllers with the same names and override certain methods
|
||||
- `services`: You can extend the plugin's services by create services with the same names and override certain methods
|
||||
|
||||
---
|
||||
|
||||
## Policies
|
||||
|
||||
Policies are functions which have the ability to execute specific logic on each request before it reaches the controller's action. They are mostly used for securing business logic easily.
|
||||
Each route of the project can be associated to an array of policies. For example, you can create a policy named `isAdmin`, which obviously checks that the request is sent by an admin user, and use it for critical routes.
|
||||
|
||||
Policies can be:
|
||||
|
||||
- `global`: so they can be used within the entire project.
|
||||
- `scoped`: used by single API or plugin.
|
||||
|
||||
### Where are the policies defined?
|
||||
|
||||
The API and plugins policies (scoped) are defined in each `./api/**/config/policies/` folders and plugins. They are respectively exposed through `strapi.api.**.config.policies` and `strapi.plugins.**.config.policies`. The global policies are defined at `./config/policies/` and accessible via `strapi.config.policies`.
|
||||
|
||||
::: note
|
||||
Please refer to the [policy guide](../guides/policies.md)
|
||||
:::
|
||||
|
||||
### Global policies
|
||||
|
||||
Global policies are reusable through the entire app.
|
||||
|
||||
::: note
|
||||
Please refer to the [global policy guide](../guides/policies.md#global-policies)
|
||||
:::
|
||||
|
||||
### Scoped policies
|
||||
|
||||
A policy defined in an API or plugin is usable only from this API or plugin. You don't need any prefix to use it.
|
||||
|
||||
::: note
|
||||
Please refer to the [scoped policy guide](../guides/policies.md#scoped-policies).
|
||||
:::
|
||||
|
||||
### Plugin policies
|
||||
|
||||
Plugin policies are usable from any app API.
|
||||
|
||||
::: note
|
||||
Please refer to the [plugin policy guide](../guides/policies.md#plugins).
|
||||
:::
|
||||
|
||||
## Public Assets
|
||||
|
||||
Public assets are static files such as images, video, css, etc that you want to make accessible to the outside world. Every new project includes by default, a folder named `./public`.
|
||||
|
||||
::: note
|
||||
Please refer to the [public configuration](../configurations/configurations.md#Application) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Requests
|
||||
|
||||
The context object (`ctx`) contains all the request's related information.
|
||||
|
||||
::: note
|
||||
Please refer to the [requests guide](../guides/requests.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Responses
|
||||
|
||||
The context object (`ctx`) contains a list of values and functions useful to manage server responses.
|
||||
|
||||
::: note
|
||||
Please refer to the [responses guide](../guides/responses.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Routing
|
||||
|
||||
`./api/**/config/routes.json` files define all available routes for the clients.
|
||||
|
||||
::: note
|
||||
Please refer to the [routing guide](../guides/routing.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Services
|
||||
|
||||
Services are a set of reusable functions. They are particularly useful to respect the DRY (don’t repeat yourself) programming concept and to simplify [controllers](#controllers) logic.
|
||||
|
||||
::: note
|
||||
Please refer to the [services guide](../guides/services.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Queries
|
||||
|
||||
Queries are a way to implement database agnostic queries in strapi's core or plugins.
|
||||
|
||||
::: note
|
||||
Please refer to the [queries guide](../guides/queries.md) for more information.
|
||||
:::
|
||||
|
||||
---
|
||||
@ -2,6 +2,10 @@
|
||||
|
||||
The main configurations of the project are located in the `./config` directory. Additional configs can be added in the `./api/**/config` folder of each API and plugin by creating JavaScript or JSON files.
|
||||
|
||||
::: note
|
||||
Inside the `/config` folder, every folder will be parsed and injected into the global object `strapi.config`. Let's say, you added a folder named `credentials` with two files `stripe.json` and `paypal.json` into it. The content of these files will be accessible through `strapi.config.credentials.stripe` and `strapi.config.credentials.paypal`.
|
||||
:::
|
||||
|
||||
## Application
|
||||
|
||||
Contains the main configurations relative to your project.
|
||||
@ -45,30 +49,12 @@ Add custom configurations to the project. The content of this file is available
|
||||
|
||||
These configurations are accessible through `strapi.config.backendURL` and `strapi.config.mainColor`.
|
||||
|
||||
## Language
|
||||
|
||||
As described in the [i18n documentation](../guides/i18n.md), Strapi includes an internationalization system. This is especially useful to translate API messages (errors, etc.).
|
||||
|
||||
**Path —** `./config/language.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"enabled": true,
|
||||
"defaultLocale": "en_us",
|
||||
"modes": ["query", "subdomain", "cookie", "header", "url", "tld"],
|
||||
"cookieName": "locale"
|
||||
}
|
||||
```
|
||||
|
||||
- `enabled` (boolean): Enable or disable i18n. Default value: `true`.
|
||||
- `defaultLocale` (string): Default locale used by the application. Default value: `en_us`.
|
||||
- `modes` (array): Methods used to detect client language. Default value: `["query", "subdomain", "cookie", "header", "url", "tld"]`.
|
||||
- `cookieName` (string): Name of the cookie used to store the locale name. Default value: `locale`.
|
||||
|
||||
## Functions
|
||||
|
||||
The `./config/functions/` folder contains a set of JavaScript files in order to add dynamic and logic based configurations.
|
||||
|
||||
All functions that are expose in this folder or in your `./config` folder are accessible via `strapi.config.functions['fileName']();`
|
||||
|
||||
### Bootstrap
|
||||
|
||||
**Path —** `./config/functions/bootstrap.js`.
|
||||
@ -147,13 +133,17 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
### Bookshelf, Mongoose
|
||||
### Database ORM customization
|
||||
|
||||
**Path —** `./config/functions/bookshelf.js`.
|
||||
**Path —** `./config/functions/mongoose.js`.
|
||||
- **Path —** `./config/functions/bookshelf.js`.
|
||||
- **Path —** `./config/functions/mongoose.js`.
|
||||
|
||||
When present, they are loaded to let you customize your database connection instance, for example for adding some plugin, customizing parameters, etc.
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "Mongoose" id="mongoose"
|
||||
|
||||
As an example, for using the `mongoose-simple-random` plugin for MongoDB, you can register it like this:
|
||||
|
||||
**Path —** `./config/functions/mongoose.js`.
|
||||
@ -168,6 +158,10 @@ module.exports = (mongoose, connection) => {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "Bookshelf" id="bookshelf"
|
||||
|
||||
Another example would be using the `bookshelf-uuid` plugin for MySQL, you can register it like this:
|
||||
|
||||
**Path —** `./config/functions/bookshelf.js`.
|
||||
@ -180,26 +174,10 @@ module.exports = (bookshelf, connection) => {
|
||||
};
|
||||
```
|
||||
|
||||
## Locales
|
||||
|
||||
The `locales` directory contains the translations of your API.
|
||||
|
||||
Each JSON file located in the folder must have the name of its corresponding translation (eg. `en_US.json`, `fr_FR.json`, etc.). Each line defines a translation key and its corresponding value.
|
||||
|
||||
#### Example
|
||||
|
||||
**Path —** `./config/locales/en_US.json`.
|
||||
|
||||
```js
|
||||
{
|
||||
"welcome": "Welcome"
|
||||
}
|
||||
```
|
||||
|
||||
::: note
|
||||
Take a look at the [internationalization's guide](../guides/i18n.md) for more details.
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Environments
|
||||
|
||||
Most of the application's configurations are defined by environment. It means that you can specify settings for each environment (`development`, `production`, `test`, etc.).
|
||||
@ -212,22 +190,26 @@ You can access the config of the current environment through `strapi.config.curr
|
||||
|
||||
**Path —** `./config/environments/**/database.json`.
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "Bookshelf" id="bookshelf"
|
||||
|
||||
- `defaultConnection` (string): Connection by default for models which are not related to a specific `connection`. Default value: `default`.
|
||||
- `connections` List of all available connections.
|
||||
- `default`
|
||||
- `connector` (string): Connector used by the current connection. Default value: `strapi-hook-mongoose`.
|
||||
- `connector` (string): Connector used by the current connection. Will be `strapi-hook-bookshelf`.
|
||||
- `settings` Useful for external session stores such as Redis.
|
||||
- `client` (string): Database client to create the connection. Default value: `mongo`.
|
||||
- `client` (string): Database client to create the connection. `sqlite` or `postgres` or `mysql`.
|
||||
- `host` (string): Database host name. Default value: `localhost`.
|
||||
- `port` (integer): Database port. Default value: `27017`.
|
||||
- `database` (string): Database name. Default value: `development`.
|
||||
- `port` (integer): Database port.
|
||||
- `database` (string): Database name.
|
||||
- `username` (string): Username used to establish the connection.
|
||||
- `password` (string): Password used to establish the connection.
|
||||
- `options` (object): List of additional options used by the connector.
|
||||
- `timezone` (string): Set the default behavior for local time (used only for a SQL database). Default value: `utc`.
|
||||
- `schema` (string): Set the default database schema. (used only for Postgres DB)
|
||||
- `timezone` (string): Set the default behavior for local time. Default value: `utc`.
|
||||
- `schema` (string): Set the default database schema. **Used only for Postgres DB**
|
||||
- `ssl` (boolean): For ssl database connection.
|
||||
- `options` Options used for database connection.
|
||||
- `ssl` (boolean): For ssl database connection.
|
||||
- `debug` (boolean): Show database exchanges and errors.
|
||||
- `autoMigration` (boolean): To disable auto tables/columns creation for SQL database.
|
||||
- `pool` Options used for database connection pooling. For more information look at [Knex's pool config documentation](https://knexjs.org/#Installation-pooling).
|
||||
@ -239,46 +221,70 @@ You can access the config of the current environment through `strapi.config.curr
|
||||
- `reapIntervalMillis` (integer): How often to check for idle connections in milliseconds. Default value: `1000` (1 second).
|
||||
- `createRetryIntervalMillis` (integer): How long to idle after a failed create before trying again in milliseconds. Default value: `200`.
|
||||
|
||||
:::
|
||||
|
||||
::: tab "Mongoose" id="mongoose"
|
||||
|
||||
- `defaultConnection` (string): Connection by default for models which are not related to a specific `connection`. Default value: `default`.
|
||||
- `connections` List of all available connections.
|
||||
- `default`
|
||||
- `connector` (string): Connector used by the current connection. Will be `strapi-hook-mongoose`.
|
||||
- `settings` Useful for external session stores such as Redis.
|
||||
- `client` (string): Database client to create the connection. Will be `mongo`.
|
||||
- `host` (string): Database host name. Default value: `localhost`.
|
||||
- `port` (integer): Database port. Default value: `27017`.
|
||||
- `database` (string): Database name.
|
||||
- `username` (string): Username used to establish the connection.
|
||||
- `password` (string): Password used to establish the connection.
|
||||
- `options` Options used for database connection.
|
||||
- `ssl` (boolean): For ssl database connection.
|
||||
- `debug` (boolean): Show database exchanges and errors.
|
||||
- `authenticationDatabase` (string): Connect with authentication.
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
#### Example
|
||||
|
||||
**Path —** `./config/environments/**/database.json`.
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "Postgres" id="postgres"
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"default": {
|
||||
"connector": "strapi-hook-mongoose",
|
||||
"settings": {
|
||||
"client": "mongo",
|
||||
"host": "localhost",
|
||||
"port": 27017,
|
||||
"database": "development",
|
||||
"username": "fooUsername",
|
||||
"password": "fooPwd"
|
||||
},
|
||||
"options": {
|
||||
"authenticationDatabase": "",
|
||||
"ssl": true,
|
||||
"minimize": true
|
||||
}
|
||||
},
|
||||
"postgres": {
|
||||
"connector": "strapi-hook-bookshelf",
|
||||
"settings": {
|
||||
"client": "postgres",
|
||||
"host": "localhost",
|
||||
"port": 5432,
|
||||
"username": "${process.env.USERNAME}",
|
||||
"password": "${process.env.PWD}",
|
||||
"password": "${process.env.PASSWORD}",
|
||||
"database": "strapi",
|
||||
"schema": "public"
|
||||
},
|
||||
"options": {
|
||||
"debug": true
|
||||
}
|
||||
},
|
||||
"mysql": {
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "MySQL" id="mysql"
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"default": {
|
||||
"connector": "strapi-hook-bookshelf",
|
||||
"settings": {
|
||||
"client": "mysql",
|
||||
@ -286,10 +292,22 @@ You can access the config of the current environment through `strapi.config.curr
|
||||
"port": 5432,
|
||||
"username": "strapi",
|
||||
"password": "root",
|
||||
"database": ""
|
||||
"database": "strapi"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "SQLite" id="sqlite"
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"sqlite": {
|
||||
"connector": "strapi-hook-bookshelf",
|
||||
"settings": {
|
||||
@ -304,6 +322,37 @@ You can access the config of the current environment through `strapi.config.curr
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "Mongo" id="mongo"
|
||||
|
||||
```json
|
||||
{
|
||||
"defaultConnection": "default",
|
||||
"connections": {
|
||||
"default": {
|
||||
"connector": "strapi-hook-mongoose",
|
||||
"settings": {
|
||||
"client": "mongo",
|
||||
"host": "localhost",
|
||||
"port": 27017,
|
||||
"database": "strapi",
|
||||
"username": "",
|
||||
"password": ""
|
||||
},
|
||||
"options": {
|
||||
"authenticationDatabase": "",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
::: note
|
||||
Please refer to the [dynamic configurations section](#dynamic-configurations) to use global environment variable to configure the databases.
|
||||
:::
|
||||
@ -461,7 +510,7 @@ In any JSON configurations files in your project, you can inject dynamic values
|
||||
You can't execute functions inside the curly braces. Only strings are allowed.
|
||||
:::
|
||||
|
||||
## Database configuration
|
||||
## Configuration in database
|
||||
|
||||
Configuration files are not multi server friendly. So we created a data store for config you will want to update in production.
|
||||
|
||||
@ -1,6 +1,23 @@
|
||||
# Controllers
|
||||
|
||||
See the [controllers' concepts](../concepts/concepts.md#controllers) for a simple overview.
|
||||
## Concept
|
||||
|
||||
Controllers are JavaScript files which contain a set of methods called **actions** reached by the client according to the requested route. It means that every time a client requests the route, the action performs the business logic coded and sends back the response. They represent the _C_ in the _MVC_ pattern. In most cases, the controllers will contain the bulk of a project's business logic.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// GET /hello
|
||||
index: async ctx => {
|
||||
ctx.send('Hello World!');
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
In this example, any time a web browser is pointed to the `/hello` URL on your app, the page will display the text: `Hello World!`.
|
||||
|
||||
### Where are the controllers defined?
|
||||
|
||||
The controllers are defined in each `./api/**/controllers/` folders. Every JavaScript file put in these folders will be loaded as a controller. They are also available through the `strapi.controllers` and `strapi.api.**.controllers` global variables. By convention, controllers' names should be Pascal-cased, so that every word in the file (include the first one) is capitalized `User.js`, `LegalEntity.js`.
|
||||
|
||||
## Core controllers
|
||||
|
||||
@ -26,6 +43,10 @@ const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
|
||||
- `parseMultipartData`: This function parses strapi's formData format.
|
||||
- `sanitizeEntity`: This function removes all private fields from the model and its relations.
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "find" id="find"
|
||||
|
||||
#### `find`
|
||||
|
||||
```js
|
||||
@ -49,6 +70,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "findOne" id="findone"
|
||||
|
||||
#### `findOne`
|
||||
|
||||
```js
|
||||
@ -66,6 +91,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "count" id="count"
|
||||
|
||||
#### `count`
|
||||
|
||||
```js
|
||||
@ -85,6 +114,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "create" id="create"
|
||||
|
||||
#### `create`
|
||||
|
||||
```js
|
||||
@ -108,6 +141,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "update" id="update"
|
||||
|
||||
#### `update`
|
||||
|
||||
```js
|
||||
@ -132,6 +169,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "delete" id="delete"
|
||||
|
||||
#### `delete`
|
||||
|
||||
```js
|
||||
@ -149,6 +190,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Custom controllers
|
||||
|
||||
You can also create custom controllers to build your own business logic and API endpoints.
|
||||
@ -163,7 +208,7 @@ There are two ways to create a controller:
|
||||
### Adding Endpoints
|
||||
|
||||
Each controller’s action must be an `async` function.
|
||||
Every action receives a `context` (`ctx`) object as first parameter containing the [request context](../guides/requests.md) and the [response context](../guides/responses.md).
|
||||
Every action receives a `context` (`ctx`) object as first parameter containing the [request context](./requests-responses.md) and the [response context](./requests-responses.md).
|
||||
|
||||
::: note
|
||||
Every action must be referenced by a route.
|
||||
29
docs/3.0.0-beta.x/concepts/customization.md
Normal file
29
docs/3.0.0-beta.x/concepts/customization.md
Normal file
@ -0,0 +1,29 @@
|
||||
# Customization
|
||||
|
||||
## Plugin extensions
|
||||
|
||||
In strapi you can install plugins in your `node_modules`. This allows for easy updates and respect best practices. To customize those installed plugins you can work in the `/extensions` directory. It contains all the plugins' customizable files.
|
||||
|
||||
Some plugins will create files in these folders so you can then modify them. You can also create certain files manually to add some custom configuration for example.
|
||||
|
||||
Extensions folder structure:
|
||||
|
||||
- `extensions/`
|
||||
- `**`: Plugin Id
|
||||
- `admin`: You can extend a plugin's admin by creating a file with the same name, doing so will override the original one.
|
||||
- `config`: You can extend a plugin's configuration by adding a settings.json file with your custom configuration
|
||||
- `models`: Contains the plugin's models that you have overwritten (e.g: When you add a relation to the User model)
|
||||
- `controllers`: You can extend the plugin's controllers by creating controllers with the same names and override certain methods
|
||||
- `services`: You can extend the plugin's services by creating services with the same names and override certain methods
|
||||
|
||||
## Admin extension
|
||||
|
||||
The admin panel is a `node_module` that is similar to a plugin but the slight difference that it encapsulate all the installed plugin of your application.
|
||||
|
||||
To extend this package you will have to create an `admin` folder at the root of your application.
|
||||
|
||||
In this folder you will be able to override admin flies and functions.
|
||||
|
||||
::: note
|
||||
For more details, visit the [admin panel constomization](../admin-panel/customization.md) documentation.
|
||||
:::
|
||||
37
docs/3.0.0-beta.x/concepts/file-structure.md
Normal file
37
docs/3.0.0-beta.x/concepts/file-structure.md
Normal file
@ -0,0 +1,37 @@
|
||||
# Files structure
|
||||
|
||||
By default, your project's structure will look like this:
|
||||
|
||||
- `/api`: contains the business logic of your project split in sub-folder per API.
|
||||
- `**`
|
||||
- `/config`: contains the API's configurations ([`routes`](./routing.md), [`policies`](./policies.md), etc).
|
||||
- [`/controllers`](./controllers.md): contains the API's custom controllers.
|
||||
- [`/models`](./models.md): contains the API's models.
|
||||
- [`/services`](./services.md): contains the API's custom services.
|
||||
- `/node_modules`: contains the npm's packages used by the project.
|
||||
- [`/config`](./configurations.md)
|
||||
- [`/environments`](./configurations.md#environments): contains the project's configurations per environment.
|
||||
- `/**`
|
||||
- `/development`
|
||||
- [`custom.json`](./configurations.md#custom): contains the custom configurations for this environment.
|
||||
- [`database.json`](./configurations.md#database): contains the database connections for this environment.
|
||||
- [`request.json`](./configurations.md#request): contains the request settings for this environment.
|
||||
- [`response.json`](./configurations.md#response): contains the response settings for this environment.
|
||||
- [`server.json`](./configurations.md#server): contains the server settings for this environment.
|
||||
- `/production`
|
||||
- `/staging`
|
||||
- [`/functions`](./configurations.md#functions): contains lifecycle or generic functions of the project.
|
||||
- [`bootstrap.js`](./configurations.md#bootstrap): contains the code executed at the application start.
|
||||
- [`cron.js`](./configurations.md#cron-tasks): contains the cron tasks.
|
||||
- [`application.json`](./configurations.md#application): contains the general configurations of the project.
|
||||
- [`custom.json`](./configurations.md#custom): contains the custom configurations of the project.
|
||||
- [`hook.json`](./configurations.md#hook): contains the hook settings of the project.
|
||||
- [`middleware.json`](./configurations.md#middleware): contains the middleware settings of the project.
|
||||
- [`/hooks`](./hooks.md): contains the custom hooks of the project.
|
||||
- [`/middlewares`](./middlewares.md): contains the custom middlewares of the project.
|
||||
- [`/admin`](../admin-panel/customization.md): contains your admin customization files.
|
||||
- [`/extensions`](./customization.md): contains the files to extend installed plugins.
|
||||
- [`/plugins`](./plugins.md): contains your local plugins.
|
||||
- [`/public`](./public-assets.md): contains the file accessible to the outside world.
|
||||
- `/build`: contains your admin panel UI build.
|
||||
- `/.cache`: contains files used to build your admin panel.
|
||||
@ -1,6 +1,55 @@
|
||||
# Models
|
||||
|
||||
See the [models' concepts](../concepts/concepts.md#models) for details.
|
||||
## Concept
|
||||
|
||||
Models are a representation of the database's structure and lifecycle. They are split into two separate files. A JavaScript file that contains the lifecycle callbacks, and a JSON one that represents the data stored in the database and their format. The models also allow you to define the relationships between them.
|
||||
|
||||
**Path —** `./api/user/models/User.js`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
beforeSave: next => {
|
||||
// Use `this` to get your current object
|
||||
next();
|
||||
},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
afterSave: (doc, next) => {
|
||||
next();
|
||||
},
|
||||
|
||||
// ... and more
|
||||
};
|
||||
```
|
||||
|
||||
**Path —** `./api/user/models/User.settings.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"connection": "default",
|
||||
"info": {
|
||||
"name": "user",
|
||||
"description": "This represents the User Model"
|
||||
},
|
||||
"attributes": {
|
||||
"firstname": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastname": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, there is a `User` model which contains two attributes `firstname` and `lastname`.
|
||||
|
||||
### Where are the models defined?
|
||||
|
||||
The models are defined in each `./api/**/models/` folder. Every JavaScript or JSON file in these folders will be loaded as a model. They are also available through the `strapi.models` and `strapi.api.**.models` global variables. Usable everywhere in the project, they contain the ORM model object that they are refer to. By convention, models' names should be written in lowercase.
|
||||
|
||||
## How to create a model?
|
||||
|
||||
@ -19,7 +68,32 @@ This will create two files located at `./api/user/models`:
|
||||
when you create a new API using the CLI (`strapi generate:api <name>`), a model is automatically created.
|
||||
:::
|
||||
|
||||
## Model Information
|
||||
## Model settings
|
||||
|
||||
Additional settings can be set on models:
|
||||
|
||||
- `connection` (string) - Connection's name which must be used. Default value: `default`.
|
||||
- `collectionName` (string) - Collection's name (or table's name) in which the data should be stored.
|
||||
- `globalId` (string) -Global variable name for this model (case-sensitive).
|
||||
|
||||
**Path —** `User.settings.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"connection": "mongo",
|
||||
"collectionName": "Users_v1",
|
||||
"globalId": "Users",
|
||||
"attributes": {}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the model `User` will be accessible through the `Users` global variable. The data will be stored in the `Users_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
|
||||
|
||||
::: note
|
||||
The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.
|
||||
:::
|
||||
|
||||
## Model information
|
||||
|
||||
The info key on the model-json states information about the model. This information is used in the admin interface, when showing the model.
|
||||
|
||||
@ -27,6 +101,17 @@ The info key on the model-json states information about the model. This informat
|
||||
- `description`: The description of the model.
|
||||
- `mainField`: Determines which model-attribute is shown when displaying the model.
|
||||
|
||||
**Path —** `User.settings.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"info": {
|
||||
"name": "user",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Model options
|
||||
|
||||
The options key on the model-json states.
|
||||
@ -34,7 +119,17 @@ The options key on the model-json states.
|
||||
- `idAttribute`: This tells the model which attribute to expect as the unique identifier for each database row (typically an auto-incrementing primary key named 'id'). _Only valid for strapi-hook-bookshelf_
|
||||
- `idAttributeType`: Data type of `idAttribute`, accepted list of value below. _Only valid for strapi-hook-bookshelf_
|
||||
- `timestamps`: This tells the model which attributes to use for timestamps. Accepts either `boolean` or `Array` of strings where first element is create date and second element is update date. Default value when set to `true` for Bookshelf is `["created_at", "updated_at"]` and for MongoDB is `["createdAt", "updatedAt"]`.
|
||||
- `uuid` : Boolean to enable UUID support on MySQL, you will need to set the `idAttributeType` to `uuid` as well and install the `bookshelf-uuid` package. To load the package you can see [this example](../configurations/configurations.md#bookshelf-mongoose).
|
||||
- `uuid` : Boolean to enable UUID support on MySQL, you will need to set the `idAttributeType` to `uuid` as well and install the `bookshelf-uuid` package. To load the package you can see [this example](./configurations.md#bookshelf-mongoose).
|
||||
|
||||
**Path —** `User.settings.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"options": {
|
||||
"timestamps": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Define the attributes
|
||||
|
||||
@ -122,11 +217,15 @@ To improve the Developer eXperience when developing or using the administration
|
||||
|
||||
## Relations
|
||||
|
||||
Refer to the [relations concept](../concepts/concepts.md#relations) for more information about relations type.
|
||||
Relations let your create links (relations) between your Content Types.
|
||||
|
||||
### One-way
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
Refer to the [one-way concept](../concepts/concepts.md#one-way) for information.
|
||||
::: tab "One-Way" id="one-way"
|
||||
|
||||
### One-Way
|
||||
|
||||
One-way relationships are useful to link an entry to another. However, only one of the models can be queried with its populated items.
|
||||
|
||||
#### Example
|
||||
|
||||
@ -173,9 +272,13 @@ xhr.send(
|
||||
);
|
||||
```
|
||||
|
||||
### One-to-one
|
||||
:::
|
||||
|
||||
Refer to the [one-to-one concept](../concepts/concepts.md#one-to-one) for information.
|
||||
::: tab "One-to-One" id="one-to-one"
|
||||
|
||||
### One-to-One
|
||||
|
||||
One-to-One relationships are usefull when you have one entity that could be linked to only one other entity. And vis versa.
|
||||
|
||||
#### Example
|
||||
|
||||
@ -250,9 +353,13 @@ xhr.send(
|
||||
);
|
||||
```
|
||||
|
||||
### One-to-many
|
||||
:::
|
||||
|
||||
Refer to the [one-to-many concept](../concepts/concepts.md#one-to-many) for more information.
|
||||
::: tab "One-to-Many" id="one-to-many"
|
||||
|
||||
### One-to-Many
|
||||
|
||||
One-to-Many relationships are usefull when an entry can be liked to multiple entries of an other Content Type. And an entry of the other Content Type can be linked to only one entry.
|
||||
|
||||
#### Example
|
||||
|
||||
@ -337,9 +444,13 @@ xhr.send(
|
||||
);
|
||||
```
|
||||
|
||||
### Many-to-many
|
||||
:::
|
||||
|
||||
Refer to the [many-to-many concept](../concepts/concepts.md#many-to-many).
|
||||
::: tab "Many-to-Many" id="many-to-many"
|
||||
|
||||
### Many-to-Many
|
||||
|
||||
One-to-Many relationships are usefull when an entry can be liked to multiple entries of an other Content Type. And an entry of the other Content Type can be linked to many entries.
|
||||
|
||||
#### Example
|
||||
|
||||
@ -359,9 +470,8 @@ A `product` can be related to many `categories`, so a `category` can have many `
|
||||
}
|
||||
```
|
||||
|
||||
::: note
|
||||
**NOTE**:
|
||||
(NoSQL databases only) The `dominant` key defines which table/collection should store the array that defines the relationship. Because there are no join tables in NoSQL, this key is required for NoSQL databases (ex: MongoDB).
|
||||
:::
|
||||
|
||||
**Path —** `./api/category/models/Category.settings.json`.
|
||||
|
||||
@ -420,19 +530,20 @@ xhr.send(
|
||||
);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "Polymorphic" id="polymorphic"
|
||||
|
||||
### Polymorphic
|
||||
|
||||
The polymorphic relationships are the solution when you don't know which kind of model will be associated to your entry. A common use case is an `Image` model that can be associated to many others kind of models (Article, Product, User, etc).
|
||||
|
||||
Refer to the [upload plugin](../plugins/upload.md) polymorphic implementation for more information.
|
||||
|
||||
#### Single vs Many
|
||||
|
||||
Let's stay with our `Image` model which might belongs to **a single `Article` or `Product` entry**.
|
||||
|
||||
::: note
|
||||
**NOTE**:
|
||||
In other words, it means that an `Image` entry can be associated to one entry. This entry can be a `Article` or `Product` entry.
|
||||
:::
|
||||
|
||||
**Path —** `./api/image/models/Image.settings.json`.
|
||||
|
||||
@ -449,9 +560,8 @@ In other words, it means that an `Image` entry can be associated to one entry. T
|
||||
|
||||
Also, our `Image` model which might belongs to **many `Article` or `Product` entries**.
|
||||
|
||||
::: note
|
||||
**NOTE**:
|
||||
In other words, it means that an `Article` entry can relate to the same image as a `Product` entry.
|
||||
:::
|
||||
|
||||
**Path —** `./api/image/models/Image.settings.json`.
|
||||
|
||||
@ -663,9 +773,8 @@ CREATE TABLE `image` (
|
||||
)
|
||||
```
|
||||
|
||||
::: note
|
||||
**NOTE**:
|
||||
If you've overridden the default table name given by Strapi by using the `collectionName` attribute. Use the value set in the `collectionName` to name the table.
|
||||
:::
|
||||
|
||||
The second table will allow us to associate one or many others entries to the `Image` model. The name of the table is the same as the previous one with the suffix `_morph`.
|
||||
|
||||
@ -694,42 +803,84 @@ CREATE TABLE `image_morph` (
|
||||
| 2 | 4738 | 58 | article | avatar |
|
||||
| 3 | 1738 | 71 | article | avatar |
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Lifecycle callbacks
|
||||
|
||||
Refer to the [lifecycle callbacks concepts](../concepts/concepts.md#lifecycle-callbacks) for information.
|
||||
::: warning
|
||||
The life cycle functions are based on the ORM life cycle and not on the strapi request.
|
||||
We are currently woking on it to make it easier to use and understand.
|
||||
Please check [this issue](https://github.com/strapi/strapi/issues/1443) on GitHub.
|
||||
:::
|
||||
|
||||
The following events are available by default:
|
||||
|
||||
Callbacks on `save`:
|
||||
Callbacks on:
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "save" id="save"
|
||||
|
||||
`save`
|
||||
|
||||
- beforeSave
|
||||
- afterSave
|
||||
|
||||
Callbacks on `fetch`:
|
||||
:::
|
||||
|
||||
::: tab "fetch" id="fetch"
|
||||
|
||||
`fetch`
|
||||
|
||||
- beforeFetch
|
||||
- afterFetch
|
||||
|
||||
Callbacks on `fetchAll`:
|
||||
::: tab "fetchAll" id="fetchall"
|
||||
|
||||
`fetchAll`
|
||||
|
||||
- beforeFetchAll
|
||||
- afterFetchAll
|
||||
|
||||
Callbacks on `create`:
|
||||
:::
|
||||
|
||||
::: tab "create" id="create"
|
||||
|
||||
`create`
|
||||
|
||||
- beforeCreate
|
||||
- afterCreate
|
||||
|
||||
Callbacks on `update`:
|
||||
:::
|
||||
|
||||
::: tab "update" id="update"
|
||||
|
||||
`update`
|
||||
|
||||
- beforeUpdate
|
||||
- afterUpdate
|
||||
|
||||
Callbacks on `destroy`:
|
||||
:::
|
||||
|
||||
::: tab "destroy" id="destroy"
|
||||
|
||||
destroy`
|
||||
|
||||
- beforeDestroy
|
||||
- afterDestroy
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
### Example
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "Mongoose" id="mongoose"
|
||||
|
||||
#### Mongoose
|
||||
|
||||
The entry is available through the `model` parameter
|
||||
@ -753,6 +904,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "Bookshelf" id="bookshelf"
|
||||
|
||||
#### Bookshelf
|
||||
|
||||
Each of these functions receives a three parameters `model`, `attrs` and `options`. You have to return a Promise.
|
||||
@ -776,27 +931,6 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
## Settings
|
||||
|
||||
Additional settings can be set on models:
|
||||
|
||||
- `connection` (string) - Connection's name which must be used. Default value: `default`.
|
||||
- `collectionName` (string) - Collection's name (or table's name) in which the data should be stored.
|
||||
- `globalId` (string) -Global variable name for this model (case-sensitive).
|
||||
|
||||
**Path —** `User.settings.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"connection": "mongo",
|
||||
"collectionName": "Users_v1",
|
||||
"globalId": "Users",
|
||||
"attributes": {}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the model `User` will be accessible through the `Users` global variable. The data will be stored in the `Users_v1` collection or table and the model will use the `mongo` connection defined in `./config/environments/**/database.json`
|
||||
|
||||
::: note
|
||||
The `connection` value can be changed whenever you want, but you should be aware that there is no automatic data migration process. Also if the new connection doesn't use the same ORM you will have to rewrite your queries.
|
||||
:::
|
||||
|
||||
:::::
|
||||
@ -1,12 +1,12 @@
|
||||
# Prameters
|
||||
|
||||
## Programmatic usage
|
||||
## Concept
|
||||
|
||||
You can use `strapi-utils` to parse the query params to Strapi's standards filters programmatically if you need it.
|
||||
|
||||
### Extracting requests filters
|
||||
## Extracting requests filters
|
||||
|
||||
To transform the query params to Strapi's standard filters a request, you can use the `convertRestQueryParams` function from [strapi-utils](../global-strapi/reference.md#strapiutils).
|
||||
To transform the query params to Strapi's standard filters a request, you can use the `convertRestQueryParams` function from [strapi-utils](../global-strapi/api-reference.md#strapiutils).
|
||||
|
||||
```js
|
||||
const { convertRestQueryParams } = require('strapi-utils');
|
||||
@ -32,7 +32,7 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
### Querying data
|
||||
## Querying data
|
||||
|
||||
We added a new API to query data base on the new filters API.
|
||||
|
||||
@ -53,15 +53,15 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
#### SQL databases (strapi-hook-bookshelf)
|
||||
### SQL databases (strapi-hook-bookshelf)
|
||||
|
||||
If you are using a SQL database, calling `buildQuery` will return a [`Bookshelf Query`](https://bookshelfjs.org/api.html) on which you can call other functions (e.g `count`)
|
||||
|
||||
#### Mongo database
|
||||
### Mongo database
|
||||
|
||||
If you are using a mongo database calling `buildQuery` returns either a [`Mongoose Query`](https://mongoosejs.com/docs/api.html#Query) or a custom query when used with deep filtering.
|
||||
|
||||
##### Custom Query
|
||||
#### Custom Query
|
||||
|
||||
When using the deep filtering feature with mongo, we build an aggregation query to avoid too many round-trips with the mongo DB.
|
||||
Doing that means we don't get a Mongoose object as a response but instead a plain JS Object. This brings a some issues like no virtual fields available and no Mongoose lifecycles.
|
||||
7
docs/3.0.0-beta.x/concepts/plugins.md
Normal file
7
docs/3.0.0-beta.x/concepts/plugins.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Plugins
|
||||
|
||||
A plugin is like a small independent sub-application. It has its own business logic with dedicated models, controllers, services, middlewares or hooks. It can also have it's own UI integrated in the admin panel.
|
||||
|
||||
::: note
|
||||
Please refer to the [plugins documentation](../plugin-development/quick-start.md) for more information.
|
||||
:::
|
||||
@ -1,6 +1,30 @@
|
||||
# Policies
|
||||
|
||||
See the [policies' concepts](../concepts/concepts.md#policies) for details.
|
||||
## Concept
|
||||
|
||||
Policies are functions which have the ability to execute specific logic on each request before it reaches the controller's action. They are mostly used for securing business logic easily.
|
||||
Each route of the project can be associated to an array of policies. For example, you can create a policy named `isAdmin`, which obviously checks that the request is sent by an admin user, and use it for critical routes.
|
||||
|
||||
Policies can be:
|
||||
|
||||
- `global`: so they can be used within the entire project.
|
||||
- `scoped`: used by single API or plugin.
|
||||
|
||||
### Where are the policies defined?
|
||||
|
||||
The API and plugins policies (scoped) are defined in each `./api/**/config/policies/` folders and plugins. They are respectively exposed through `strapi.api.**.config.policies` and `strapi.plugins.**.config.policies`. The global policies are defined at `./config/policies/` and accessible via `strapi.config.policies`.
|
||||
|
||||
### Global policies
|
||||
|
||||
Global policies are reusable through the entire app.
|
||||
|
||||
### Scoped policies
|
||||
|
||||
A policy defined in an API or plugin is usable only from this API or plugin. You don't need any prefix to use it.
|
||||
|
||||
### Plugin policies
|
||||
|
||||
Plugin policies are usable from any app API.
|
||||
|
||||
## How to create a policy?
|
||||
|
||||
@ -30,17 +54,15 @@ You can access to any controllers, services or models thanks to the global varia
|
||||
|
||||
## Usage
|
||||
|
||||
To apply policies to a route, you need to associate an array of policies to it. As explained in the [policies' concepts](../concepts/concepts.md#policies), there are two kinds of policies: global or scoped.
|
||||
To apply policies to a route, you need to associate an array of policies to it. There are two kinds of policies: global or scoped.
|
||||
|
||||
### Global policies
|
||||
|
||||
Refer to the [concept](../concepts/concepts.md#policies) for details.
|
||||
|
||||
The global policies can be associated to any routes in your project.
|
||||
|
||||
**Path —** `./api/restaurant/routes.json`.
|
||||
|
||||
```js
|
||||
```json
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
@ -48,9 +70,7 @@ The global policies can be associated to any routes in your project.
|
||||
"path": "/restaurants",
|
||||
"handler": "Restaurant.find",
|
||||
"config": {
|
||||
"policies": [
|
||||
"global.isAuthenticated"
|
||||
]
|
||||
"policies": ["global.isAuthenticated"]
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -65,11 +85,11 @@ You can put as much policy you want in this array. However be careful about the
|
||||
|
||||
### Plugins policies
|
||||
|
||||
Plugins can add and expose policies into your app. For example, the plugin `Auth` (COMING SOON) comes with several useful policies to ensure that the user is well authenticated or has the rights to perform an action.
|
||||
Plugins can add and expose policies into your app. For example, the plugin **Users & Permissions** comes with useful policies to ensure that the user is well authenticated or has the rights to perform an action.
|
||||
|
||||
**Path —** `./api/restaurant/config/routes.json`.
|
||||
|
||||
```js
|
||||
```json
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
@ -77,9 +97,7 @@ Plugins can add and expose policies into your app. For example, the plugin `Auth
|
||||
"path": "/restaurants",
|
||||
"handler": "Restaurant.find",
|
||||
"config": {
|
||||
"policies": [
|
||||
"plugins.users-permissions.isAuthenticated"
|
||||
]
|
||||
"policies": ["plugins.users-permissions.isAuthenticated"]
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -107,7 +125,7 @@ module.exports = async (ctx, next) => {
|
||||
|
||||
**Path —** `./api/restaurant/config/routes.json`.
|
||||
|
||||
```js
|
||||
```json
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
@ -115,9 +133,7 @@ module.exports = async (ctx, next) => {
|
||||
"path": "/restaurants",
|
||||
"handler": "Restaurant.find",
|
||||
"config": {
|
||||
"policies": [
|
||||
"isAdmin"
|
||||
]
|
||||
"policies": ["isAdmin"]
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1,6 +1,6 @@
|
||||
# Public Assets
|
||||
|
||||
See the [public assets concepts](../concepts/concepts.md#public-assets) for details.
|
||||
Public assets are static files such as images, video, css, etc that you want to make accessible to the outside world. Every new project includes by default, a folder named `./public`.
|
||||
|
||||
Because an API may need to serve static assets, every new Strapi project includes by default, a folder named `/public`. Any file located in this directory is accessible if the request's path doesn't match any other defined route and if it matches a public file name.
|
||||
|
||||
@ -16,4 +16,4 @@ An image named `company-logo.png` in `./public/` is accessible through `/company
|
||||
The dotfiles are not exposed. It means that every files with the names start by `.` such as `.htaccess` or `.gitignore` are not served.
|
||||
:::
|
||||
|
||||
Refer to the [public assets configurations](../configurations/configurations.md#Application) for more information.
|
||||
Refer to the [public assets configurations](./configurations.md#Application) for more information.
|
||||
@ -8,38 +8,9 @@ These queries handle for you specific Strapi features like `groups`, `filters` a
|
||||
|
||||
## API Reference
|
||||
|
||||
### `findOne`
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
This method returns the first entry matching some basic params.
|
||||
You can also pass a populate option to specify which relations you want to be populated.
|
||||
|
||||
#### Examples
|
||||
|
||||
**Find one by id**:
|
||||
|
||||
```js
|
||||
strapi.query('restaurant').findOne({ id: 1 });
|
||||
```
|
||||
|
||||
**Find one by name**:
|
||||
|
||||
```js
|
||||
strapi.query('restaurant').findOne({ name: 'restaurant name' });
|
||||
```
|
||||
|
||||
**Find one by name and creation_date**:
|
||||
|
||||
```js
|
||||
strapi
|
||||
.query('restaurant')
|
||||
.findOne({ name: 'restaurant name', date: '2019-01-01T00:00:00Z' });
|
||||
```
|
||||
|
||||
**Find one by id and populate a relation**
|
||||
|
||||
```js
|
||||
strapi.query('restaurant').findOne({ id: 1 }, ['category', 'category.name']);
|
||||
```
|
||||
::: tab "find" id="find"
|
||||
|
||||
### `find`
|
||||
|
||||
@ -76,6 +47,47 @@ strapi
|
||||
.find({ id_nin: [1], _start: 10 }, ['category', 'category.name']);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "findOne" id="findone"
|
||||
|
||||
### `findOne`
|
||||
|
||||
This method returns the first entry matching some basic params.
|
||||
You can also pass a populate option to specify which relations you want to be populated.
|
||||
|
||||
#### Examples
|
||||
|
||||
**Find one by id**:
|
||||
|
||||
```js
|
||||
strapi.query('restaurant').findOne({ id: 1 });
|
||||
```
|
||||
|
||||
**Find one by name**:
|
||||
|
||||
```js
|
||||
strapi.query('restaurant').findOne({ name: 'restaurant name' });
|
||||
```
|
||||
|
||||
**Find one by name and creation_date**:
|
||||
|
||||
```js
|
||||
strapi
|
||||
.query('restaurant')
|
||||
.findOne({ name: 'restaurant name', date: '2019-01-01T00:00:00Z' });
|
||||
```
|
||||
|
||||
**Find one by id and populate a relation**
|
||||
|
||||
```js
|
||||
strapi.query('restaurant').findOne({ id: 1 }, ['category', 'category.name']);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "create" id="create"
|
||||
|
||||
### `create`
|
||||
|
||||
Creates an entry in the database and returns the entry.
|
||||
@ -105,6 +117,10 @@ strapi.query('restaurant').create({
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "update" id="update"
|
||||
|
||||
### `update`
|
||||
|
||||
Updates an entry in the database and returns the entry.
|
||||
@ -180,6 +196,10 @@ strapi.query('restaurant').update(
|
||||
);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "delete" id="delete"
|
||||
|
||||
### `delete`
|
||||
|
||||
Deletes and entry and return its value before deletion.
|
||||
@ -199,6 +219,10 @@ strapi.query('restaurant').delete({ id: 1 });
|
||||
strapi.query('restaurant').delete({ district: '_18th' });
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "count" id="count"
|
||||
|
||||
### `count`
|
||||
|
||||
Returns the count of entries matching Strapi filters.
|
||||
@ -223,6 +247,10 @@ strapi.query('restaurant').count({ name_contains: 'food' });
|
||||
strapi.query('restaurant').count({ date_lt: '2019-08-01T00:00:00Z' });
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "search" id="search"
|
||||
|
||||
### `search`
|
||||
|
||||
Returns entries based on a search on all fields allowing it. (this feature will return all entries on sqlite).
|
||||
@ -245,6 +273,10 @@ strapi
|
||||
.search({ _q: 'my search query', _limit: 100, _sort: 'date:desc' });
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "countSearch" id="countsearch"
|
||||
|
||||
### `countSearch`
|
||||
|
||||
Returns the total count of entries based on a search. (this feature will return all entries on sqlite).
|
||||
@ -255,6 +287,10 @@ Returns the total count of entries based on a search. (this feature will return
|
||||
strapi.query('restaurant').countSearch({ _q: 'my search query' });
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Custom Queries
|
||||
|
||||
When you want to customize your services or create new ones you will have to build your queries with the underlying ORM models.
|
||||
@ -267,6 +303,10 @@ strapi.query(modelName, plugin).model;
|
||||
|
||||
Then you can run any queries available on the model. You should refer to the specific ORM documentation for more details:
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "Bookshelf" id="bookshelf"
|
||||
|
||||
### Bookshelf
|
||||
|
||||
Documentation: [https://bookshelfjs.org/](https://bookshelfjs.org/)
|
||||
@ -284,6 +324,10 @@ const result = await strapi
|
||||
const fields = result.toJSON();
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "Mongoose" id="mongoose"
|
||||
|
||||
### Mongoose
|
||||
|
||||
Documentation: [https://mongoosejs.com/](https://mongoosejs.com/)
|
||||
@ -297,3 +341,7 @@ const result = strapi.query('restaurant').model.find({
|
||||
|
||||
const fields = result.toObject();
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
13
docs/3.0.0-beta.x/concepts/requests-responses.md
Normal file
13
docs/3.0.0-beta.x/concepts/requests-responses.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Requests and responses
|
||||
|
||||
## Request
|
||||
|
||||
The context object (`ctx`) contains all the requests related information. They are accessible through `ctx.request`, from [controllers](controllers.md) and [policies](policies.md).
|
||||
|
||||
For more information, please refer to the [Koa request documentation](http://koajs.com/#request).
|
||||
|
||||
## Responses
|
||||
|
||||
The context object (`ctx`) contains a list of values and functions useful to manage server responses. They are accessible through `ctx.response`, from [controllers](controllers.md) and [policies](policies.md).
|
||||
|
||||
For more information, please refer to the [Koa response documentation](http://koajs.com/#response).
|
||||
@ -1,6 +1,10 @@
|
||||
# Routing
|
||||
|
||||
See the [routing's concept](../concepts/concepts.md#routing) for details.
|
||||
## Concept
|
||||
|
||||
`./api/**/config/routes.json` files define all available endpoints for the clients.
|
||||
|
||||
By default Strapi generate endpoints for all your Content Type. More information in the [Content API](../content-api/api-endpoints.md) documentation.
|
||||
|
||||
## How to create a route?
|
||||
|
||||
@ -14,12 +18,18 @@ You have to edit the `routes.json` file in one of your APIs folders (`./api/**/c
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/restaurants",
|
||||
"handler": "Restaurant.find"
|
||||
"handler": "Restaurant.find",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": ["POST", "PUT"],
|
||||
"path": "/restaurants/:id",
|
||||
"handler": "Restaurant.createOrUpdate"
|
||||
"handler": "Restaurant.createOrUpdate",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
@ -37,7 +47,7 @@ You have to edit the `routes.json` file in one of your APIs folders (`./api/**/c
|
||||
- `path` (string): URL starting with `/` (ex: `/restaurants`)
|
||||
- `handler` (string): Action to executed when the route is hit following this syntax `<Controller>.<action>`
|
||||
- `config`
|
||||
- `policies` (array): Array of policies names or path ([see more](../guides/policies.md))
|
||||
- `policies` (array): Array of policies names or path ([see more](./policies.md))
|
||||
- `prefix` (string): Set a prefix to this route. Also, it will be loaded into the main router (useful feature for plugin)
|
||||
|
||||
## Dynamic parameters
|
||||
@ -50,12 +60,18 @@ The router used by Strapi allows you to create dynamic routes where you can use
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/restaurants/:category/:id",
|
||||
"handler": "Restaurant.findOneByCategory"
|
||||
"handler": "Restaurant.findOneByCategory",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/restaurants/:region(\\d{2}|\\d{3})/:id", // Only match when the first parameter contains 2 or 3 digits.
|
||||
"handler": "Restaurant.findOneByRegion"
|
||||
"handler": "Restaurant.findOneByRegion",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -71,7 +87,10 @@ By default, the main route of the server `/` is pointed to the `/public/index.ht
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/",
|
||||
"handler": "Controller.name"
|
||||
"handler": "Controller.name",
|
||||
"config": {
|
||||
"policies": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
# Services
|
||||
|
||||
See the [services concept](../concepts/concepts.md#services) for an overview.
|
||||
## Concept
|
||||
|
||||
Services are a set of reusable functions. They are particularly useful to respect the DRY (don’t repeat yourself) programming concept and to simplify [controllers](./controllers.md) logic.
|
||||
|
||||
## Core services
|
||||
|
||||
@ -17,6 +19,10 @@ You can read about `strapi.query` calls [here](./queries.md)
|
||||
In the following example your controller, service and model is named `restaurant`
|
||||
:::
|
||||
|
||||
:::: tabs cache-lifetime="10" :options="{ useUrlFragment: false }"
|
||||
|
||||
::: tab "find" id="find"
|
||||
|
||||
#### `find`
|
||||
|
||||
```js
|
||||
@ -32,6 +38,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "findOne" id="findone"
|
||||
|
||||
#### `findOne`
|
||||
|
||||
```js
|
||||
@ -48,6 +58,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "count" id="count"
|
||||
|
||||
#### `count`
|
||||
|
||||
```js
|
||||
@ -64,6 +78,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "create" id="create"
|
||||
|
||||
#### `create`
|
||||
|
||||
```js
|
||||
@ -88,6 +106,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "update" id="update"
|
||||
|
||||
#### `update`
|
||||
|
||||
```js
|
||||
@ -112,6 +134,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "delete" id="delete"
|
||||
|
||||
#### `delete`
|
||||
|
||||
```js
|
||||
@ -128,6 +154,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "search" id="search"
|
||||
|
||||
#### `search`
|
||||
|
||||
```js
|
||||
@ -144,6 +174,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::: tab "countSearch" id="countsearch"
|
||||
|
||||
#### `countSearch`
|
||||
|
||||
```js
|
||||
@ -159,6 +193,10 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
::::
|
||||
|
||||
## Custom services
|
||||
|
||||
You can also create custom services to build your own business logic.
|
||||
@ -71,7 +71,7 @@ This feature doesn't allow you to filter nested models, e.g `Find users and only
|
||||
To achieve this, there are two options:
|
||||
|
||||
- Either build a custom route or modify your services
|
||||
- Use [GraphQL](../guides/graphql.md#query-api)
|
||||
- Use [GraphQL](../plugins/graphql.md#query-api)
|
||||
:::
|
||||
|
||||
::: warning
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Reference
|
||||
# API reference
|
||||
|
||||
- strapi
|
||||
- [.admin](#strapi-admin)
|
||||
@ -73,7 +73,7 @@ Returns an object of plugins available within the project. Each plugin object co
|
||||
## strapi.query
|
||||
|
||||
This utility function allows to bind models with query functions specific to each ORM (e.g: `mongoose` or `bookshelf`).
|
||||
For more details, see the [Queries section](../guides/queries.md).
|
||||
For more details, see the [Queries section](../concepts/queries.md).
|
||||
|
||||
## strapi.reload
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
# Internationalization
|
||||
|
||||
See the [internationalization' concepts](../concepts/concepts.md#internationalization-and-localization) for details.
|
||||
|
||||
Because an API may need to send different data based on the language of the user, Strapi provides a built-in strategy to handle the internationalization (i18n).
|
||||
|
||||
## Usage
|
||||
|
||||
The `i18n` method that will allow you to retrieve the right string based on the language is accessible through the request's context.
|
||||
|
||||
There are many strategies to define the language that the server should use to return the correct translation. It can be based on the `locale` query parameter, the `cookie` or the `Accept-Language` header.
|
||||
|
||||
- Query: Add the `locale` parameter in the URL `GET /hello/John?locale=en_US`.
|
||||
- Cookie: Set the `locale` field in the cookie `locale=en\-US;`.
|
||||
- Header: Set the `Accept-Language` header with the value `en_US`.
|
||||
|
||||
::: note
|
||||
Please refer to the [language configuration](../configurations/configurations.md#language)
|
||||
:::
|
||||
|
||||
### Example
|
||||
|
||||
Let's say we want to say `Hello John` in english and `Bonjour Tom` in french. We need to use the built-in `i18n` feature and replace the string based on the received name.
|
||||
|
||||
**Path —** `./api/hello/config/routes.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"routes": [
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/hello/:name",
|
||||
"handler": "Hello.sayHello"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Path —** `./api/hello/controllers/Hello.js`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// GET /hello/:name
|
||||
sayHello: async ctx => {
|
||||
ctx.send(ctx.i18n.__('Hello %s', ctx.params.name));
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
You need to define the english and french translation for this key.
|
||||
|
||||
**Path —** `./config/locales/en_US.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"Hello %s": "Hello %s"
|
||||
}
|
||||
```
|
||||
|
||||
**Path —** `./config/locales/fr_FR.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"Hello %s": "Bonjour %s"
|
||||
}
|
||||
```
|
||||
|
||||
That's all! The request `GET /hello/John?locale=en_US` will return `Hello John` and `GET /hello/Tom?locale=fr_FR` will return `Bonjour Tom`
|
||||
@ -1,394 +0,0 @@
|
||||
# Request
|
||||
|
||||
See the [requests concepts](../concepts/concepts.md#requests) for details.
|
||||
|
||||
The context object (`ctx`) contains all the requests related information. They are accessible through `ctx.request`, from [controllers](controllers.md) and [policies](policies.md).
|
||||
|
||||
## API Reference
|
||||
|
||||
For more information, please refer to the [Koa request documentation](http://koajs.com/#request).
|
||||
|
||||
### request.header
|
||||
|
||||
Request header object.
|
||||
|
||||
### request.header=
|
||||
|
||||
Set request header object.
|
||||
|
||||
### request.headers
|
||||
|
||||
Request header object. Alias as `request.header`.
|
||||
|
||||
### request.headers=
|
||||
|
||||
Set request header object. Alias as `request.header=`.
|
||||
|
||||
### request.method
|
||||
|
||||
Request method.
|
||||
|
||||
### request.method=
|
||||
|
||||
Set request method, useful for implementing middleware
|
||||
such as `methodOverride()`.
|
||||
|
||||
### request.length
|
||||
|
||||
Return request Content-Length as a number when present, or `undefined`.
|
||||
|
||||
### request.url
|
||||
|
||||
Get request URL.
|
||||
|
||||
### request.url=
|
||||
|
||||
Set request URL, useful for url rewrites.
|
||||
|
||||
### request.originalUrl
|
||||
|
||||
Get request original URL.
|
||||
|
||||
### request.origin
|
||||
|
||||
Get origin of URL, include `protocol` and `host`.
|
||||
|
||||
```js
|
||||
ctx.request.origin;
|
||||
// => http://example.com
|
||||
```
|
||||
|
||||
### request.href
|
||||
|
||||
Get full request URL, include `protocol`, `host` and `url`.
|
||||
|
||||
```js
|
||||
ctx.request.href;
|
||||
// => http://example.com/foo/bar?q=1
|
||||
```
|
||||
|
||||
### request.path
|
||||
|
||||
Get request pathname.
|
||||
|
||||
### request.path=
|
||||
|
||||
Set request pathname and retain query-string when present.
|
||||
|
||||
### request.querystring
|
||||
|
||||
Get raw query string void of `?`.
|
||||
|
||||
### request.querystring=
|
||||
|
||||
Set raw query string.
|
||||
|
||||
### request.search
|
||||
|
||||
Get raw query string with the `?`.
|
||||
|
||||
### request.search=
|
||||
|
||||
Set raw query string.
|
||||
|
||||
### request.host
|
||||
|
||||
Get host (hostname:port) when present. Supports `X-Forwarded-Host`
|
||||
when `app.proxy` is **true**, otherwise `Host` is used.
|
||||
|
||||
### request.hostname
|
||||
|
||||
Get hostname when present. Supports `X-Forwarded-Host`
|
||||
when `app.proxy` is **true**, otherwise `Host` is used.
|
||||
|
||||
If host is IPv6, Koa delegates parsing to
|
||||
[WHATWG URL API](https://nodejs.org/dist/latest-v8.x/docs/api/url.html#url_the_whatwg_url_api),
|
||||
_Note_ This may impact performance.
|
||||
|
||||
### request.URL
|
||||
|
||||
Get WHATWG parsed URL object.
|
||||
|
||||
### request.type
|
||||
|
||||
Get request `Content-Type` void of parameters such as "charset".
|
||||
|
||||
```js
|
||||
const ct = ctx.request.type;
|
||||
// => "image/png"
|
||||
```
|
||||
|
||||
### request.charset
|
||||
|
||||
Get request charset when present, or `undefined`:
|
||||
|
||||
```js
|
||||
ctx.request.charset;
|
||||
// => "utf-8"
|
||||
```
|
||||
|
||||
### request.query
|
||||
|
||||
Get parsed query-string, returning an empty object when no
|
||||
query-string is present. Note that this getter does _not_
|
||||
support nested parsing.
|
||||
|
||||
For example "color=blue&size=small":
|
||||
|
||||
```js
|
||||
{
|
||||
color: 'blue',
|
||||
size: 'small'
|
||||
}
|
||||
```
|
||||
|
||||
### request.query=
|
||||
|
||||
Set query-string to the given object. Note that this
|
||||
setter does _not_ support nested objects.
|
||||
|
||||
```js
|
||||
ctx.query = { next: '/login' };
|
||||
```
|
||||
|
||||
### request.fresh
|
||||
|
||||
Check if a request cache is "fresh", aka the contents have not changed. This
|
||||
method is for cache negotiation between `If-None-Match` / `ETag`, and `If-Modified-Since` and `Last-Modified`. It should be referenced after setting one or more of these response headers.
|
||||
|
||||
```js
|
||||
// freshness check requires status 20x or 304
|
||||
ctx.status = 200;
|
||||
ctx.set('ETag', '123');
|
||||
|
||||
// cache is ok
|
||||
if (ctx.fresh) {
|
||||
ctx.status = 304;
|
||||
return;
|
||||
}
|
||||
|
||||
// cache is stale
|
||||
// fetch new data
|
||||
ctx.body = await db.find('something');
|
||||
```
|
||||
|
||||
### request.stale
|
||||
|
||||
Inverse of `request.fresh`.
|
||||
|
||||
### request.protocol
|
||||
|
||||
Return request protocol, "https" or "http". Supports `X-Forwarded-Proto`
|
||||
when `app.proxy` is **true**.
|
||||
|
||||
### request.secure
|
||||
|
||||
Shorthand for `ctx.protocol == "https"` to check if a request was
|
||||
issued via TLS.
|
||||
|
||||
### request.ip
|
||||
|
||||
Request remote address. Supports `X-Forwarded-For` when `app.proxy`
|
||||
is **true**.
|
||||
|
||||
### request.ips
|
||||
|
||||
When `X-Forwarded-For` is present and `app.proxy` is enabled an array
|
||||
of these ips is returned, ordered from upstream -> downstream. When disabled
|
||||
an empty array is returned.
|
||||
|
||||
### request.subdomains
|
||||
|
||||
Return subdomains as an array.
|
||||
|
||||
Subdomains are the dot-separated parts of the host before the main domain of
|
||||
the app. By default, the domain of the app is assumed to be the last two
|
||||
parts of the host. This can be changed by setting `app.subdomainOffset`.
|
||||
|
||||
For example, if the domain is "tobi.ferrets.example.com":
|
||||
If `app.subdomainOffset` is not set, `ctx.subdomains` is `["ferrets", "tobi"]`.
|
||||
If `app.subdomainOffset` is 3, `ctx.subdomains` is `["tobi"]`.
|
||||
|
||||
### request.is(types...)
|
||||
|
||||
Check if the incoming request contains the "Content-Type"
|
||||
header field, and it contains any of the five mime `type`s.
|
||||
If there is no request body, `null` is returned.
|
||||
If there is no content type, or the match fails `false` is returned.
|
||||
Otherwise, it returns the matching content-type.
|
||||
|
||||
```js
|
||||
// With Content-Type: text/html; charset=utf-8
|
||||
ctx.is('html'); // => 'html'
|
||||
ctx.is('text/html'); // => 'text/html'
|
||||
ctx.is('text/*', 'text/html'); // => 'text/html'
|
||||
|
||||
// When Content-Type is application/json
|
||||
ctx.is('json', 'urlencoded'); // => 'json'
|
||||
ctx.is('application/json'); // => 'application/json'
|
||||
ctx.is('html', 'application/*'); // => 'application/json'
|
||||
|
||||
ctx.is('html'); // => false
|
||||
```
|
||||
|
||||
For example if you want to ensure that
|
||||
only images are sent to a given route:
|
||||
|
||||
```js
|
||||
if (ctx.is('image/*')) {
|
||||
// process
|
||||
} else {
|
||||
ctx.throw(415, 'images only!');
|
||||
}
|
||||
```
|
||||
|
||||
### Content Negotiation
|
||||
|
||||
Koa's `request` object includes helpful content negotiation utilities powered by [accepts](http://github.com/expressjs/accepts) and [negotiator](https://github.com/federomero/negotiator). These utilities are:
|
||||
|
||||
- `request.accepts(types)`
|
||||
- `request.acceptsEncodings(types)`
|
||||
- `request.acceptsCharsets(charsets)`
|
||||
- `request.acceptsLanguages(langs)`
|
||||
|
||||
If no types are supplied, **all** acceptable types are returned.
|
||||
|
||||
If multiple types are supplied, the best match will be returned. If no matches are found, a `false` is returned, and you should send a `406 "Not Acceptable"` response to the client.
|
||||
|
||||
In the case of missing accept headers where any type is acceptable, the first type will be returned. Thus, the order of types you supply is important.
|
||||
|
||||
### request.accepts(types)
|
||||
|
||||
Check if the given `type(s)` is acceptable, returning the best match when true, otherwise `false`. The `type` value may be one or more mime type string
|
||||
such as "application/json", the extension name
|
||||
such as "json", or an array `["json", "html", "text/plain"]`.
|
||||
|
||||
```js
|
||||
// Accept: text/html
|
||||
ctx.accepts('html');
|
||||
// => "html"
|
||||
|
||||
// Accept: text/*, application/json
|
||||
ctx.accepts('html');
|
||||
// => "html"
|
||||
ctx.accepts('text/html');
|
||||
// => "text/html"
|
||||
ctx.accepts('json', 'text');
|
||||
// => "json"
|
||||
ctx.accepts('application/json');
|
||||
// => "application/json"
|
||||
|
||||
// Accept: text/*, application/json
|
||||
ctx.accepts('image/png');
|
||||
ctx.accepts('png');
|
||||
// => false
|
||||
|
||||
// Accept: text/*;q=.5, application/json
|
||||
ctx.accepts(['html', 'json']);
|
||||
ctx.accepts('html', 'json');
|
||||
// => "json"
|
||||
|
||||
// No Accept header
|
||||
ctx.accepts('html', 'json');
|
||||
// => "html"
|
||||
ctx.accepts('json', 'html');
|
||||
// => "json"
|
||||
```
|
||||
|
||||
You may call `ctx.accepts()` as many times as you like,
|
||||
or use a switch:
|
||||
|
||||
```js
|
||||
switch (ctx.accepts('json', 'html', 'text')) {
|
||||
case 'json':
|
||||
break;
|
||||
case 'html':
|
||||
break;
|
||||
case 'text':
|
||||
break;
|
||||
default:
|
||||
ctx.throw(406, 'json, html, or text only');
|
||||
}
|
||||
```
|
||||
|
||||
### request.acceptsEncodings(encodings)
|
||||
|
||||
Check if `encodings` are acceptable, returning the best match when true, otherwise `false`. Note that you should include `identity` as one of the encodings!
|
||||
|
||||
```js
|
||||
// Accept-Encoding: gzip
|
||||
ctx.acceptsEncodings('gzip', 'deflate', 'identity');
|
||||
// => "gzip"
|
||||
|
||||
ctx.acceptsEncodings(['gzip', 'deflate', 'identity']);
|
||||
// => "gzip"
|
||||
```
|
||||
|
||||
When no arguments are given all accepted encodings
|
||||
are returned as an array:
|
||||
|
||||
```js
|
||||
// Accept-Encoding: gzip, deflate
|
||||
ctx.acceptsEncodings();
|
||||
// => ["gzip", "deflate", "identity"]
|
||||
```
|
||||
|
||||
Note that the `identity` encoding (which means no encoding) could be unacceptable if the client explicitly sends `identity;q=0`. Although this is an edge case, you should still handle the case where this method returns `false`.
|
||||
|
||||
### request.acceptsCharsets(charsets)
|
||||
|
||||
Check if `charsets` are acceptable, returning
|
||||
the best match when true, otherwise `false`.
|
||||
|
||||
```js
|
||||
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
|
||||
ctx.acceptsCharsets('utf-8', 'utf-7');
|
||||
// => "utf-8"
|
||||
|
||||
ctx.acceptsCharsets(['utf-7', 'utf-8']);
|
||||
// => "utf-8"
|
||||
```
|
||||
|
||||
When no arguments are given all accepted charsets
|
||||
are returned as an array:
|
||||
|
||||
```js
|
||||
// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
|
||||
ctx.acceptsCharsets();
|
||||
// => ["utf-8", "utf-7", "iso-8859-1"]
|
||||
```
|
||||
|
||||
### request.acceptsLanguages(langs)
|
||||
|
||||
Check if `langs` are acceptable, returning
|
||||
the best match when true, otherwise `false`.
|
||||
|
||||
```js
|
||||
// Accept-Language: en;q=0.8, es, pt
|
||||
ctx.acceptsLanguages('es', 'en');
|
||||
// => "es"
|
||||
|
||||
ctx.acceptsLanguages(['en', 'es']);
|
||||
// => "es"
|
||||
```
|
||||
|
||||
When no arguments are given all accepted languages
|
||||
are returned as an array:
|
||||
|
||||
```js
|
||||
// Accept-Language: en;q=0.8, es, pt
|
||||
ctx.acceptsLanguages();
|
||||
// => ["es", "pt", "en"]
|
||||
```
|
||||
|
||||
### request.idempotent
|
||||
|
||||
Check if the request is idempotent.
|
||||
|
||||
### request.socket
|
||||
|
||||
Return the request socket.
|
||||
|
||||
### request.get(field)
|
||||
|
||||
Return request header.
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,127 +0,0 @@
|
||||
# Filters
|
||||
|
||||
See the [filters' concepts](../concepts/concepts.md#filters) for details.
|
||||
|
||||
::: note
|
||||
by default, the filters can only be used from `find` endpoints generated by the Content Type Builder and the [CLI](../cli/CLI.md). If you need to implement a filters system somewhere else, read the [programmatic usage](#programmatic-usage) section.
|
||||
:::
|
||||
|
||||
## Available operators
|
||||
|
||||
The available operators are separated in four different categories:
|
||||
|
||||
- [Filters](#filters)
|
||||
- [Sort](#sort)
|
||||
- [Limit](#limit)
|
||||
- [Start](#start)
|
||||
|
||||
### Filters
|
||||
|
||||
Easily filter results according to fields values.
|
||||
|
||||
- `=`: Equals
|
||||
- `_ne`: Not equals
|
||||
- `_lt`: Lower than
|
||||
- `_gt`: Greater than
|
||||
- `_lte`: Lower than or equal to
|
||||
- `_gte`: Greater than or equal to
|
||||
- `_contains`: Contains
|
||||
- `_containss`: Contains case sensitive
|
||||
- `_in`: Matches any value in the array of values
|
||||
- `_nin`: Doesn't match any value in the array of values
|
||||
- `_null`: Equals null/Not equals null
|
||||
|
||||
#### Examples
|
||||
|
||||
Find users having `John` as first name.
|
||||
|
||||
`GET /user?firstName=John`
|
||||
|
||||
Find products having a price equal or greater than `3`.
|
||||
|
||||
`GET /product?price_gte=3`
|
||||
|
||||
### Sort
|
||||
|
||||
Sort according to a specific field.
|
||||
|
||||
#### Example
|
||||
|
||||
Sort users by email.
|
||||
|
||||
- ASC: `GET /user?_sort=email:asc`
|
||||
- DESC: `GET /user?_sort=email:desc`
|
||||
|
||||
### Limit
|
||||
|
||||
Limit the size of the returned results.
|
||||
|
||||
#### Example
|
||||
|
||||
Limit the result length to 30.
|
||||
|
||||
`GET /user?_limit=30`
|
||||
|
||||
### Start
|
||||
|
||||
Skip a specific number of entries (especially useful for pagination).
|
||||
|
||||
#### Example
|
||||
|
||||
Get the second page of results.
|
||||
|
||||
`GET /user?_start=10&_limit=10`
|
||||
|
||||
## Programmatic usage
|
||||
|
||||
Requests system can be implemented in custom code sections.
|
||||
|
||||
### Extracting requests filters
|
||||
|
||||
To extract the filters from an JavaScript object or a request, you need to call the [`strapi.utils.models.convertParams` helper](../api-reference/reference.md#strapiutils).
|
||||
|
||||
::: note
|
||||
The returned objects is formatted according to the ORM used by the model.
|
||||
:::
|
||||
|
||||
#### Example
|
||||
|
||||
**Path —** `./api/user/controllers/User.js`.
|
||||
|
||||
```js
|
||||
// Define a list of params.
|
||||
const params = {
|
||||
_limit: 20,
|
||||
_sort: 'email',
|
||||
};
|
||||
|
||||
// Convert params.
|
||||
const formattedParams = strapi.utils.models.convertParams('user', params); // { limit: 20, sort: 'email' }
|
||||
```
|
||||
|
||||
### Query usage
|
||||
|
||||
#### Example
|
||||
|
||||
**Path —** `./api/user/controllers/User.js`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
|
||||
find: async (ctx) => {
|
||||
// Convert params.
|
||||
const formattedParams = strapi.utils.models.convertParams('user', ctx.request.query);
|
||||
|
||||
// Get the list of users according to the request query.
|
||||
const filteredUsers = await User
|
||||
.find()
|
||||
.where(formattedParams.where)
|
||||
.sort(formattedParams.sort)
|
||||
.skip(formattedParams.start)
|
||||
.limit(formattedParams.limit);
|
||||
|
||||
// Finally, send the results to the client.
|
||||
ctx.body = filteredUsers;
|
||||
};
|
||||
};
|
||||
```
|
||||
@ -383,6 +383,26 @@ Add the language translation in `packages/strapi-plugin-users-permissions/admin/
|
||||
|
||||
These two change will set up the popup message that appears in the UI. That's it, now you should be able to use your new provider.
|
||||
|
||||
## Email templates
|
||||
## Templating emails
|
||||
|
||||
[See the documentation on GitHub](https://github.com/strapi/strapi/blob/master/packages/strapi-plugin-users-permissions/docs/email-templates.md)
|
||||
By default, this plugin comes with only one template (reset password) for the moment. More templates will come later. The templates use Lodash' template() method to populate the variables.
|
||||
|
||||
You can update these template in the **Email Templates** tab in the admin panel.
|
||||
|
||||
### Reset Password
|
||||
|
||||
- `USER` (object)
|
||||
- `username`
|
||||
- `email`
|
||||
- ...and every other fields that you added manually in the model.
|
||||
- `TOKEN` corresponds to the token generated to be able to reset the password.
|
||||
- `URL` is the link where the user will be redirected after clicking on it in the email.
|
||||
|
||||
### Email address confirmation
|
||||
|
||||
- `USER` (object)
|
||||
- `username`
|
||||
- `email`
|
||||
- ...and every other fields that you added manually in the model.
|
||||
- `CODE` corresponds to the CODE generated to be able confirm the user email.
|
||||
- `URL` is the Strapi backend URL that confirm the code (by default `/auth/email-confirmation`).
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"Analytics": "Analytics",
|
||||
"Content Manager": "Inhalts-Manager",
|
||||
"Content Type Builder": "Inhaltstyp-Manager",
|
||||
"Documentation": "Dokumentation",
|
||||
"Email": "E-Mail",
|
||||
"Files Upload": "Dateien hochladen",
|
||||
"HomePage.notification.newsLetter.success": "Newsletter erfolgreich abonniert",
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"Analytics": "Analytics",
|
||||
"Content Manager": "Content Manager",
|
||||
"Content Type Builder": "Content Type Builder",
|
||||
"Documentation": "Documentation",
|
||||
"Email": "Email",
|
||||
"Files Upload": "Files Upload",
|
||||
"HomePage.notification.newsLetter.success": "Successfully subscribed to the newsletter",
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"Analytics": "Аналитика",
|
||||
"Content Manager": "Редактор контента",
|
||||
"Content Type Builder": "Типы Контента",
|
||||
"Documentation": "Документация",
|
||||
"Email": "Email",
|
||||
"Files Upload": "Загрузка файлов",
|
||||
"HomePage.notification.newsLetter.success": "Успешная подписка на рассылку новостей",
|
||||
|
||||
@ -81,6 +81,7 @@
|
||||
"video-react": "^0.13.2",
|
||||
"webpack": "^4.40.1",
|
||||
"webpackbar": "^3.2.0",
|
||||
"webpack-dev-server": "^3.4.1",
|
||||
"yup": "^0.27.0"
|
||||
},
|
||||
"author": {
|
||||
@ -104,7 +105,6 @@
|
||||
"devDependencies": {
|
||||
"chokidar": "^3.1.1",
|
||||
"webpack": "^4.40.1",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-server": "^3.4.1"
|
||||
"webpack-cli": "^3.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ module.exports = {
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchCollection: async (model, columns, options) => {},
|
||||
@ -20,7 +20,7 @@ module.exports = {
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchCollection: async (model, columns, options) => {},
|
||||
|
||||
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
/* eslint-disable prefer-template */
|
||||
export default (location, n) => {
|
||||
const half = location.split(n + '=')[1];
|
||||
return half !== undefined ? decodeURIComponent(half.split('&')[0]) : null;
|
||||
|
||||
if (half !== undefined) {
|
||||
try {
|
||||
return decodeURIComponent(half.split('&')[0]);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@ -56,7 +56,7 @@ module.exports = function(strapi) {
|
||||
password,
|
||||
database,
|
||||
srv,
|
||||
useUnifiedTopology
|
||||
useUnifiedTopology,
|
||||
} = connection.settings;
|
||||
|
||||
const uriOptions = uri ? url.parse(uri, true).query : {};
|
||||
@ -93,9 +93,9 @@ module.exports = function(strapi) {
|
||||
* https://github.com/Automattic/mongoose/issues/6881 */
|
||||
await instance.connect(
|
||||
uri ||
|
||||
`mongodb${isSrv ? '+srv' : ''}://${username}:${password}@${host}${
|
||||
!isSrv ? ':' + port : ''
|
||||
}/`,
|
||||
`mongodb${isSrv ? '+srv' : ''}://${username}:${encodeURIComponent(
|
||||
password
|
||||
)}@${host}${!isSrv ? ':' + port : ''}/`,
|
||||
connectOptions
|
||||
);
|
||||
} catch (error) {
|
||||
|
||||
@ -4,5 +4,6 @@
|
||||
"shadowCRUD": true,
|
||||
"playgroundAlways": false,
|
||||
"depthLimit": 7,
|
||||
"amountLimit": 100
|
||||
"amountLimit": 100,
|
||||
"shareEnabled": false
|
||||
}
|
||||
|
||||
@ -92,6 +92,7 @@ module.exports = strapi => {
|
||||
) {
|
||||
serverParams.playground = {
|
||||
endpoint: strapi.plugins.graphql.config.endpoint,
|
||||
shareEnabled: strapi.plugins.graphql.config.shareEnabled
|
||||
};
|
||||
|
||||
serverParams.introspection = true;
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
"EditPage.notification.policies.error": "Beim Abruf von policies ist ein Fehler aufgetreten",
|
||||
"EditPage.notification.role.error": "Beim Abruf der Rolle ist ein Fehler aufgetreten",
|
||||
"EditPage.submit": "Speichern",
|
||||
"Email.template.email_confirmation": "Betsätigung der E-Mail Adresse",
|
||||
"Email.template.email_confirmation": "Bestätigung der E-Mail Adresse",
|
||||
"Email.template.reset_password": "Passwort zurücksetzen",
|
||||
"Email.template.success_register": "Anmeldung erfolgreich",
|
||||
"Email.template.validation_email": "Validierung der E-Mail-Adresse",
|
||||
|
||||
@ -15,11 +15,13 @@ module.exports = async () => {
|
||||
const jwtSecret = uuid();
|
||||
_.set(strapi.plugins['users-permissions'], 'config.jwtSecret', jwtSecret);
|
||||
|
||||
strapi.reload.isWatching = false;
|
||||
await strapi.fs.writePluginFile(
|
||||
'users-permissions',
|
||||
'config/jwt.json',
|
||||
JSON.stringify({ jwtSecret }, null, 2)
|
||||
);
|
||||
strapi.reload.isWatching = true;
|
||||
}
|
||||
|
||||
const pluginStore = strapi.store({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user