> For the complete documentation index, see [llms.txt](https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/extra-module-3-openapi-specification/discovery-service.md).

# Discovery service

A way to append decorators during system startup.

This improvement will be an opportunity to learn about a very interesting and useful tool. So far, we have these general rules for the possibility of returning these response statuses:

* <mark style="color:blue;">UNAUTHORIZED</mark>: all routes
* <mark style="color:blue;">FORBIDDEN</mark>: routes that require roles

Documenting this manually would be tedious and error-prone. Fortunately, instead we can leverage the <mark style="color:blue;">`DiscoveryService`</mark>, which allows for accessing references to all **controllers** and **providers** during system startup. This is quite useful for appending decorators dynamically, which is exactly what we'll do here. Let's then begin.

First, let's create a module to encapsule documentation mappers. In it, add the <mark style="color:blue;">`DiscoveryModule`</mark> to the <mark style="color:blue;">`imports`</mark>, in order to be able to use the <mark style="color:blue;">`DiscoveryService`</mark>.

```shellscript
nest g mo api-doc
```

Then, let's create a provider responsible for mapping response statuses.

```shellscript
nest g pr docs/response-status-mapper
```

Now, make it implement the <mark style="color:blue;">`OnApplicationBootstrap`</mark> interface. This forces the class to implement the namesake method, which executes when the app is **starting**. Now, the first step in this method will be to obtain a reference to the <mark style="color:blue;">`controllers`</mark> by using the <mark style="color:blue;">`DiscoveryService`</mark>, which we also should inject now.

```typescript
const controllers = this.discoveryService.getControllers();
```

We'll then iterate over each controller. Notice that they were returned inside **wrappers**.

```typescript
for (const wrapper of controllers) {
  // ...
}
```

Next, we'll obtain the <mark style="color:blue;">`instance`</mark> from inside each <mark style="color:blue;">`wrapper`</mark>, and then obtain the <mark style="color:blue;">`prototype`</mark> from the <mark style="color:blue;">`instance`</mark>. This will be necessary afterwards.

```typescript
const { instance } = wrapper;
const prototype = Object.getPrototypeOf(instance);
```

After that, we'll get the names of the controller's route handlers by using the <mark style="color:blue;">`metadataScanner`</mark> (also to be injected). This can be achieved by using the <mark style="color:blue;">`prototype`</mark>. Sequentially, we may obtain references to the actual route handlers by indexing these names inside the controller <mark style="color:blue;">`instance`</mark>.

```typescript
const routeNames = this.metadataScanner.getAllMethodNames(prototype);
const routes = routeNames.map((name) => instance[name] as Function);
```

{% hint style="info" %}
Note the type assertion, as otherwise each <mark style="color:blue;">`route`</mark> would be of type <mark style="color:red;">any</mark>.
{% endhint %}

And then, we'll have a reference for the <mark style="color:blue;">`controller`</mark> too. Just as we asserted the <mark style="color:blue;">`routes`</mark> as generic functions, we'll also assert the <mark style="color:blue;">`controller`</mark> as a generic class.

```typescript
const controller = instance.constructor as Type;
```

Proceeding, we'll now iterate over each <mark style="color:blue;">`route`</mark>.

```typescript
for (const route of routes) {
  // ...
}
```

As every route may return the <mark style="color:blue;">UNAUTHORIZED</mark> status, we should apply its respective decorator to each route. To append it to a route reference, use it without <mark style="color:blue;">@</mark>, and use a second pair of parentheses, passing the <mark style="color:blue;">`route`</mark>.

```typescript
ApiUnauthorizedResponse({ description: 'Unauthorized' })(route);
```

However, for organization, let's create a private method with this logic, and use it instead.

```typescript
private mapUnauthorized(route: Function) {
  // ...
}
```

The next part will be quite familiar. The logic for obtaining roles metadata from a <mark style="color:blue;">`route`</mark>/<mark style="color:blue;">`controller`</mark> can be found in the <mark style="color:blue;">`RolesGuard`</mark>. We may even copy the beginning of its <mark style="color:blue;">`canActivate()`</mark> method, as it will be nearly identical. The difference is just that we don't use a <mark style="color:blue;">`context`</mark>, and pass the <mark style="color:blue;">`route`</mark> and <mark style="color:blue;">`controller`</mark> to the <mark style="color:blue;">`reflector`</mark> directly. Just remember to inject it, of course.

```typescript
private mapForbidden(route: Function, controller: Type) {
  const requiredRoles = this.reflector.getAllAndOverride(Roles, [
    route,
    controller,
  ]);

  if (!requiredRoles) return;

  ApiForbiddenResponse({ description: 'Forbidden' })(route);
}
```

Call this method too, and we're done! Now these routes will be automatically decorated for us.

<mark style="color:green;">**Commit**</mark> - Using discovery service to automatically document routes
