# 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`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blueprint.onehilltech.com/developer-guide/services.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
