> For the complete documentation index, see [llms.txt](https://blueprint.onehilltech.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blueprint.onehilltech.com/developer-guide/services.md).

# Services

## Introduction

Services are software entities that operate in the background of the application, and outside of the [controllers](/developer-guide/routers-and-controllers/controllers.md), [routers](/developer-guide/routers-and-controllers/routers.md), and [listeners](/developer-guide/untitled.md). Services are singletons as well—meaning only one instance of the service exists at all times.

Examples of services include:

* Connection manager for MongoDB
* Local caching algorithm for a content delivery network (CDN)
* Gateway for communicating with Firebase Cloud Messaging

All services are located in `app/services`.

## Implementing a Service

You implement a service by extending the `Service` class. Here is an example service for storing the [messages we originally stored in a controller](/developer-guide/routers-and-controllers/controllers.md#action-definition).

{% code title="app/services/messages.js" %}

```javascript

const { Service } = require ('@onehilltech/blueprint');

module.exports = Service.extend ({
  _messages: null,
  
  init () {
    this._super.call (this, ...arguments);
    this._messages = [];
  },
  
  push (msg) {
    this._messages.push (msg);
  },
  
  find (id) {
    return this._messages.find (msg => msg.id === id);
  }
});
```

{% endcode %}

As shown in the example implementation above, the service has methods for adding and finding messages.

## Accessing a Service

You access a service by defining a property with the value `service([name])`. This method will bind the service to the associated property.&#x20;

{% hint style="info" %}
The name parameter is require if the (file) name of the service does not match the name of the property. For example, if a service is in a file named `local-cache`, then you must use `service('local-cache')`to access the service.
{% endhint %}

Below, we have re-implemented the message controller to use the message service.

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

module.exports = Controller.extend ({
  messages: service (),       // access the messages service
  Message: model ('message'),
  
  create () {
    return Action.extend ({
      _nextId: 0,      // id of the next message
      
      // ...
      
      execute (req, res) {
        let id = this._nextId ++;
        let data = Object.assign ({id}, pick (req.body.message, ['from','to','date','subject','content']));
        let msg = this.Message.create (data);
        
        this.controller.messages.push (msg);
        
        res.status (200).json ({message: msg});
      }
    })
  },
  
  getOne () {
    return Action.extend ({
      // ...
      
      execute (req, res) {
        const {messageId} = req.params;
        const found = this.controllers.messages.find (messageId);
        
        if (found)
          return res.status (200).json ({message: found});
        else
          return res.sendStatus (404);  
      }
    });
  }
});
```

In the example above, you will notice that the `messages` property has been changed from an array to a reference to the `messages` service. Now, the controller will read and write message to and from the `messages` service. More importantly, other entities can access this service and manipulate to the same messages this controller is able to manipulate.

## Service Lifecycle

Services are loaded automatically by the application after the application has loaded its [configuration files](/developer-guide/managing-configurations.md). Once the service is loaded into member, its lifecycle methods are called in the following order:

1. **`configure`** This method is called when the service is to configure itself. The `configure()` method should not be confused with the `init()` method. The `init()` method is for synchronous configuration whereas the `configure()` method is for asynchronous configuration. This is because the configure method can return a `Promise` to signify asynchronous configuration.
2. **`start`** This method is called when the service is started. If the service must perform any asynchronous operations, then it can return a `Promise`.
3. **`destroy`** This method is called when the service is being destroyed. If the service must perform any asynchronous operations, then it can return a `Promise`.
