> 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

This improvement will be an opportunity to learn about a very interesting and useful tool. We could make that all **non-public routes** receive the <mark style="color:blue;">`@ApiUnauthorizedResponse()`</mark> decorator, which indicates that a route may return a response with the <mark style="color:blue;">UNAUTHORIZED</mark> status. The same could be thought about the **routes that require roles**, and the <mark style="color:blue;">`@ApiForbiddenResponse()`</mark> decorator. To achieve this, we can leverage the <mark style="color:blue;">`DiscoveryService`</mark>, which allows for accessing references to all **controllers** and **providers** during system startup, which is quite useful for appending decorators dynamically, for instance. Let's then begin.

First, let's create a module to encapsule these documentation mappers.

```sh
nest g mo docs
```

Then, let's create a class for the **Unauthorized mapper**.

```sh
nest g cl docs/docs-unauthorized-mapper
```

{% hint style="info" %}
Please perform the following:

* Alter the filename to end in <mark style="color:purple;">.mapper</mark>
* Add <mark style="color:blue;">`@Injectable()`</mark>, so that it can be accessed by the **Nest IoC container**
  {% endhint %}

Now, in the module, we should add this mapper to the <mark style="color:blue;">`providers`</mark>, and the <mark style="color:blue;">`DiscoveryModule`</mark> to the <mark style="color:blue;">`imports`</mark>, in order to use the <mark style="color:blue;">`DiscoveryService`</mark>.

The next step is to, back in the class, 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
controllers.forEach((wrapper) => {
  // ...
});
```

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);
```

Some parts now will be a bit familiar. We should then use a <mark style="color:blue;">`reflector`</mark> to get the <mark style="color:blue;">isPublic</mark> metadata from the **controller** itself. Here we have no access to the <mark style="color:blue;">`context`</mark> like we did inside the guards, so we should pass <mark style="color:blue;">`instance.constructor`</mark>. If the controller is **public**, simply return.

```typescript
const isControllerPublic = this.reflector.get<boolean>(
  IS_PUBLIC_KEY,
  instance.constructor,
);
if (isControllerPublic) return;
```

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]);
```

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

```typescript
routes.forEach((route) => {
  // ...
});
```

The same process will now be performed with each handler: if it's **public**, simply return.

```typescript
const isPublic = this.reflector.get<boolean>(IS_PUBLIC_KEY, route);
if (isPublic) return;
```

Finally, to append this decorator to the route, 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);
```

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

Let's now create the **Forbidden mapper**. Please repeat the aforementioned procedure, and I'll detail then what will be different.

In this case, we'll check if the controller is **protected**, that is, if it requires roles.

```typescript
const isControllerProtected = !!this.reflector.get<Role[]>(
  ROLES_KEY,
  instance.constructor,
);
```

If it is, all its routes will be marked with the decorator and this iteration ends.

```typescript
if (isControllerProtected) {
  routes.forEach((route) => {
    ApiForbiddenResponse({ description: 'Forbidden' })(route);
  });
  return;
}
```

If not, we'll then check each handler, and it won't be marked if it's <mark style="color:red;">not</mark> protected.

```typescript
const isProtected = !!this.reflector.get<Role[]>(ROLES_KEY, route);
if (!isProtected) return;
```

We have now covered both cases with dynamic documentation. Outstanding!

<mark style="color:green;">**Commit**</mark> - Documenting forbidden routes automatically
