Service-template-node/CodingGuide

= Coding Guide =

Route Set-up
All of the routes are read from the routes directory and are automatically mounted on start-up. The first step is to create a new route file by copying the route template: Now, open  in your favourite editor. The first thing you need to decide is the mount path for the routes contained in the file and the API version the route belongs to. Let's say that this file will contain routes pertaining to famous people, so a path like  makes sense here. Obviously, the API version is going to be. Change lines 32 - 36 to reflect this: This causes all of the routes you create in  to be mounted on , where   represents the sought domain (such as  ,  , etc.).

Routes
Creating routes is accomplished by calling  where   is the HTTP verb you want to create the route for (,  ,  , etc.), and   is the callback function called when the relative path   is matched. We are now ready to set up our first route. Replace line 23 with the following code: The route's path is, which signifies a variable path. In this case, it is the name of the person the request is about. Thus, both  and   will match the route. The callback's body is rather simple: we set the response's status to  and send back a JSON containing the person's name. To learn more about routes and their various options, read Express.js' routing guide.

Promises
The service template includes the bluebird module for handling asynchronous patterns via promises. Prime examples of when they should be used are performing external requests or I/O actions. Promises allow the service process not to block on them and continue serving other requests until the action is completed.

I/O
Coming back to our example route, let's say that we want to serve a simple HTML document on the endpoint. To do so, first we need to require and promisify the  module. Put this line in the header of your routes file (right below line 6): This creates additional functions, which are promisified versions of the original ones exported by the  module. Henceforth, we can read a file either using the built-in  or its promise-aware counterpart.

Armed with this knowledge, we can now easily create a route handler: As you can see, promises allow us to specify chained actions in a natural way (using the  continuation pattern). Note that, when using promises in services derived from this template it is important that you  the promise to the caller. Doing so allows the template's framework to automatically handle any possible errors during the promise's execution.

External Requests
One other area where promises come in handy is making external requests. Suppose we want to serve the latest news about a person from Wikinews. The template includes the preq -- a module promisifying the popular request module -- which we can use right away:

Error Handling
As mentioned earlier, the template is capable of automatically handling errors for you. However, you might want to take matters into your own hands in some occasions. The template provides a convenient  object class which you can use.

Let's revise the handler for the  route. It does not seem to be very useful, as it returns the same content for any given name. We would like it to return content relevant to the person whose name was specified in the request URI by looking up the file. If the file does not exist, a  should be returned to the caller. Note that you can also attach additional debug information to the  object to help you track down bugs. This information is going to be logged, but will not reach the client, thus ensuring no sensitive information is leaked unintentionally. To do so, simply add any property you deem important when creating / throwing the error.

Logging and Metrics
Logging and metrics collection is supported out of the box via service-runner. They are exposed in route handler files via the  and   objects.

Logging
To log something, simply use. The logger itself is a bunyan wrapper, and thus supports the following levels: Additionally, it is good practice to attach a component name to the log level as it eases log indexing and filtering later in production. For example, if a log entry has the  level and pertains to one of our example routes, the log level could be set to. The  portion of the log entry can be either a string message, or any stringifiable object. As an example, let's log the person's name given to the  route and the file name that is going to be looked up: As you can see, the request object  has an additional property - , which allows you to log messages and objects in the context of the current request. To do so, it attaches a unique request ID to each logged information. If you would like to log context-free information, you can use the  object instead, even though that is not recommended.

Metrics Collection
Collecting metrics is a great way to have insights into the overall health and performance of your service. When using the template, this is as easy as calling one of the following methods: How can one collect them? Let's show it on. This route uses an external request to complete its action, which means that you have little control over your service's response time, as it is dominated by the request to Wikinews. Two interesting metrics that we can collect here (and that directly affect the service's response time) are the external request's response time and the size of its response. We can measure the former with  and the latter with. Additionally, it interesting to see the distribution of languages, which can be achieved with. For more information on the available methods, see the service-runner documentation.

Test Cases
The service needs to thoroughly tested since other services and clients are going to depend on it. The template uses mocha for test execution and provides some useful utility functions in test/utils.

To create a test suite for our example routes, create the  directory in   and two files inside of it:   and. These will test the example routes. Let's start with :