# Middleware

## How to register middleware?

The registration method for middleware is usually written in the load method

```ts
export class MyPlugin extends Plugin {
  load() {
    this.app.acl.use();
    this.app.resourcer.use();
    this.app.use();
  }
}
```

Notes.

1. `app.acl.use()` Add a resource-permission-level middleware to be executed before permission determination
2. `app.resourcer.use()` Adds a resource-level middleware that is executed only when a defined resource is requested
3. `app.use()` Add an application-level middleware to be executed on every request

## Onion Circle Model

```ts
app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(1);
  await next();
  ctx.body.push(2);
});

app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(3);
  await next();
  ctx.body.push(4);
});
```

Visit http://localhost:13000/api/hello to see that the browser responds with the following data

```js
{"data": [1,3,4,2]}
```

## Built-in middlewares and execution order

1. `cors`
2. `bodyParser`
3. `i18n`
4. `dataWrapping`
5. `db2resource` 6.
6. `restApi` 1.
   1. `parseToken` 2.
   2. `checkRole`
   3. `acl` 1.
      1. `acl.use()` Additional middleware added
   4. `resourcer.use()` Additional middleware added
   5. `action handler`
7. `app.use()` Additional middleware added

You can also use `before` or `after` to insert the middleware into the location of one of the preceding `tag`, e.g.

```ts
app.use(m1, { tag: 'restApi' });
app.resourcer.use(m2, { tag: 'parseToken' });
app.resourcer.use(m3, { tag: 'checkRole' });
// m4 will come before m1
app.use(m4, { before: 'restApi' });
// m5 will be inserted between m2 and m3
app.resourcer.use(m5, { after: 'parseToken', before: 'checkRole' });
```

If no location is specifically specified, the order of execution of the added middlewares is

1. middlewares added by `acl.use` will be executed first
2. then the ones added by `resourcer.use`, including the middleware handler and action handler
3. and finally the ones added by `app.use`

```ts
app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(1);
  await next();
  ctx.body.push(2);
});

app.resourcer.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(3);
  await next();
  ctx.body.push(4);
});

app.acl.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(5);
  await next();
  ctx.body.push(6);
});

app.resourcer.define({
  name: 'test',
  actions: {
    async list(ctx, next) {
      ctx.body = ctx.body || [];
      ctx.body.push(7);
      await next();
      ctx.body.push(8);
    },
  },
});
```

Visit http://localhost:13000/api/hello to see that the browser responds with the data

```js
{"data": [1,2]}
```

Visiting http://localhost:13000/api/test:list to see, the browser responds with the following data

```js
{"data": [5,3,7,1,2,8,4,6]}
```

### Resource undefined, middlewares added by resourcer.use() will not be executed

```ts
app.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(1);
  await next();
  ctx.body.push(2);
});

app.resourcer.use(async (ctx, next) => {
  ctx.body = ctx.body || [];
  ctx.body.push(3);
  await next();
  ctx.body.push(4);
});
```

Visit http://localhost:13000/api/hello to see that the browser responds with the following data

```js
{"data": [1,2]}
```

In the above example, the hello resource is not defined and will not enter the resourcer, so the middleware in the resourcer will not be executed

## Middleware Usage

TODO

## Example

- [samples/ratelimit](https://github.com/nocobase/nocobase/blob/main/packages/samples/ratelimit/) IP rate-limiting