Simply speaking, Service is an abstract layer which is used to encapsulate business logics in complex business circumstances, and this abstraction offers advantages as below:
- keep logics in Controller cleaner.
- keep business logics independent, since the abstracted Service can be called by many Controllers repeatedly.
- separate logics and representations, and make it easier to write test cases. Write test cases in detail referring to here.
# Usage Scenario
- Processing complex data, e.g. information to be shown need to be got from databases, and should be processed in specific rules before it can be sent and seen by the user. Or when the process is done, the database should be updated.
- Calling third party services, e.g. getting Github information etc.
# Defining Service
Framework will initialize a new Service instance for every request accessing the server, and, for the example above, several attributes are attached to
this since the Service class inherits
this.ctx: the instance of Context for current request, through which we can access many attributes and methods, encapsulated by the framework, of current request conveniently.
this.app: the instance of Application for current request, through which we can access global objects and methods provided by the framework.
this.service: Service defined by the application, through which we can access the abstract business layer, equivalent to
this.config: the application's run-time config.
error, use to print different level logs, almost the same as context logger, but it will append Service file path for quickly track.
ctx in Detail
To get the path chain of user request, the request context is injected by us during the Service initialization, so you are able to get the related information of context directly by
this.ctx in methods. For detailed information about context, please refer to Context.
ctx, we can get various convenient attributes and methods encapsulated by the framework. For example we can use:
this.ctx.curlto make network calls.
this.ctx.service.otherServiceto call other Services.
this.ctx.dbto make database calls etc, where db may be a module mounted by other plugins in advance.
- Service files must be put under the
app/servicedirectory, and multi-level directory is supported, which can be accessed by cascading directory names.
app/service/biz/user.js => ctx.service.biz.user
- one Service file can only define one Class, which should be returned by
- Service should be defined in the Class way, and the parent class must be
- Service is not a singleton but a request level object, the framework lazy-initializes it when the request
ctx.service.xxfor the first time, so the context of current request can be got from this.ctx in Service.
# Using Service
We begin to see how to use Service from a complete example below.