# Resources & Resource Controllers

In the lesson about [creating a service](https://blueprint.onehilltech.com/quick-start/my-first-application/services), we created a service to manage the rentals. We then updated the [`rental.get`](https://blueprint.onehilltech.com/quick-start/controllers#implementing-the-action) method in the rental controller to return the list of rentals managed by the rental service. There were other methods in the rental service, such as `create()`, `get(id)`, and `remove(id)`, that we did not use. So, let's update our application to provide routes that call use these methods.

## Implementing a Resource Controller

### Declaring a Resource Controller

A resource controller is a specialized controller that supports CRUD operations (*i.e.*, create, retrieve, update, and delete). Blueprint provides a base implementation of a resource controller, which you can extend in your application as needed. Since we have a service that supports CRUD operations, let's update the `rental` controller become a resource controller.

First, update the rental controller by changing `Controller` to `ResourceController`, and define the name property on the controller as `rental`.

{% code title="app/controllers/rental.js" %}

```javascript
const {
  ResourceController,
  Action,
  service
} = require ('@onehilltech/blueprint');

/**
 * @class rental
 */
module.exports = ResourceController.extend ({
  name: 'rental',
  
  rentals: service (),

  get () {
    return Action.extend ({
      execute (req, res) {
        const data = this.controller.rentals.rentals;
        res.status (200).json ({ data });
      }
    })
  }
});
```

{% endcode %}

What we did was extended the `ResourceController` instead of the `Controller`. This gives our controller the ability to selectively extend the actions defined in the `ResourceController` class. The `get()` method is one of the methods defined on the `ResourceController`, so we do not have do anything.

{% hint style="info" %}
The `ResourceController` extends the `Controller`, which is why the`ResourceController` is still considered a Controller.
{% endhint %}

We also defined the `name` property. This is a required property because the router uses this name when it is auto-generating the routes for the corresponding resource, as shown in the table below with their corresponding method on the `ResourceController`.

| **Method** | **Verb** | **Path**   | **Description**             |
| ---------- | -------- | ---------- | --------------------------- |
| `create()` | `POST`   | `/`        | Create a new resource       |
| `getAll()` | `GET`    | `/`        | Query the resources         |
| `getOne()` | `GET`    | `/:nameId` | Get a single resource       |
| `update()` | `PUT`    | `/:nameId` | Update an existing resource |
| `delete()` | `DELETE` | `/:nameId` | Delete an existing resource |

### Implementing Its Actions

When implementing the actions on of a resource controller, you only need to override methods that correspond to operations that you want to support. In our super-rental API server, we only want to support the following CRUD operations:

* `create`
* `getOne`
* `getAll`
* `delete`

{% hint style="info" %}
The `ResourceController` methods that are not overridden return a `404 Not Found` HTTP response to the client.
{% endhint %}

Let's first implement the `getOne()` and `getAll()`. The getOne() method is define an action that returns a single resource and the getAll() method is define an action that returns resources that match the query. If there is no query, then we should return all the resources. Below is the implementation of `getOne()` and `getAll()`.

{% code title="app/controllers/rental.js" %}

```javascript
const {
  ResourceController,
  Action,
  service
} = require ('@onehilltech/blueprint');

/**
 * @class rental
 */
module.exports = ResourceController.extend ({
  name: 'rental',

  rentals: service (),

  // query all the resources
  getAll () {
    return Action.extend ({
      execute (req, res) {
        const data = this.controller.rentals.rentals;
        res.status (200).json ({ data });
      }
    })
  },

  // get a single resources, or return 404 Not Found.
  getOne () {
    return Action.extend ({
      execute (req, res) {
        const { rentalId } = req.params;
        const rental = this.controller.rentals.get (rentalId);

        if (rental) {
          res.status (200).json ({ data: [rental] });
        }
        else {
          res.sendStatus (404);
        }
      }
    })
  }
});
```

{% endcode %}

�As shown in the code above, we implement `getAll()` by changing the method name from `get()` to `getAll()`. Later, we will discuss how to update the `getAll()` action to support queries. The `getOne()` method is similar to the `getAll()` method. The main difference is we extract the resource id from the `req.params.rentalId` property on the request object. This is because the resource name is used to construct the dynamic path for the resource (*e.g.*, `GET /:rentalId`).

{% hint style="info" %}
The `req` and `res` object are [Express](http://expressjs.com/) [request](http://expressjs.com/en/4x/api.html#req) and [response](http://expressjs.com/en/4x/api.html#res) objects, respectively.
{% endhint %}

Now, the route <http://localhost:5000/api/rentals> will still return the list of rentals. And, you can access the data for each rental via their own url.

* <http://localhost:5000/api/rentals/grand-old-mansion>
* <http://localhost:5000/api/rentals/urban-living>
* <http://localhost:5000/api/rentals/downtown-charm>

We can implement the `delete()` method in a similar manner as the `getOne()` method. For example, we get the resource id from `req.params.rentalId`. We then pass this value to the `remove()` method on the `rentals` service. Here is the rental controller with the `delete()` method implemented.

{% code title="app/controllers/rental.js" %}

```javascript
module.exports = ResourceController.extend ({
  /// ....
  
  delete () {
    return Action.extend ({
      execute (req, res) {
        const { rentalId } = req.params;
        const result = this.controller.rentals.remove (rentalId);

        res.status (200).json (result);
      }
    });
  }
});
```

{% endcode %}

The last method we need to implement is the `create()` method. When a client makes a request to create a rental, it will do so using the `POST` HTTP verb. The data about the rental will be available on the `req.body` property. To implement the `create()` method, we need to get the rental data from `req.body`, and pass it to the `add()` method on the `rentals` service. Below is the implementation of the `create()` method.

{% code title="app/controllers/rental.js" %}

```javascript
module.exports = ResourceController.extend ({
  // ...
  
  create () {
    return Action.extend ({
      execute (req, res) {
        const { rental } = req.body;
        this.controller.rentals.add (rental);
  
        res.status (200).json ({data: [rental]});
      }
    })
  }
});
```

{% endcode %}

## Declaring Resources in Router

We have defined the controller actions for managing the rental resources. We now need to declare the routes that invoke each action we implemented above. One approach is to define each route the same way we did when we defined the original route for getting the rentals. For example, we could update the rental router with the following specification.

{% code title="app/routers/rental.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/rentals': {
      post: { action: 'rental@create' },
      get: { action: 'rental@getAll' },

      '/:rentalId': {
        get: { action: 'rental@getOne' },
        delete: { action: 'rental@delete' },
      }
    }
  }
});
```

{% endcode %}

This approach works, but we end up writing the same code each time we need to declare the routes for  a resource. Instead, let's use the `resource` property that is available when defining a route. The following code is equivalent to the code above.�

{% code title="app/routers/rental.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/rentals': {
      resource: { controller: 'rental' }
    }
  }
});
```

{% endcode %}

The `resource` property will auto-generate the routes for a resource using the name defined by the associated resource controller. In this case, the name defined in by the rental resource controller is `rental`.&#x20;

By default, the resource property will generate routes that bind with each action supported by the resource controller. For our example, however, we only support a subset of the actions (*i.e.*, create, get, and delete). We can therefore use the `allow` property to specify the routes the resource controller supports, or `deny` to specify the routes the resource controller does not support. In our example, we are going to use the `allow` property to specify the support routes on the resource controller. Below is the updated example.&#x20;

{% code title="app/routers/rental.js" %}

```javascript
const { Router } = require ('@onehilltech/blueprint');

module.exports = Router.extend ({
  specification: {
    '/rentals': {
      resource: { 
        controller: 'rental',
        allow: ['create', 'getOne', 'getAll', 'delete'] 
      }
    }
  }
});
```

{% endcode %}

When the client tries to update a rental resource, the Blueprint application will respond with `404 Not Found`.

�

�
