Skip to content

4. Route Handler

Eduardo Veras edited this page Jul 7, 2022 · 2 revisions

The route handler function performs the main business logic of the route and sets the response.

It can be a normal function:

server.route({
	method: 'GET',
	path: '/hello',
	handler: function (request, reply) {
		return 'Hello world';
	}
});

Or an arrow function:

server.route({
	method: 'GET',
	path: '/hello',
	handler: (request, reply) => {
		return 'Hello world';
	}
});

Or an asyncronous function:

server.route({
	method: 'GET',
	path: '/hello',
	handler: async (request, reply) => {
		return 'Hello world';
	}
});

The handler function has 2 input parameters:

request

Request object model:

{
	info : {
		id : 'string', //Unique RequestID
		stage : 'string', //Context stage from Lambda (defined on serverless.yml)
		host : 'string', //Host address and port
		remoteAddress : 'string', //Remote source IP address
		isOffline : false //Indicate if the server is running using serverless-offline lib
	},
	auth : {
		isAuthenticated : false, //Return true if the route was sucessfully authenticated
		credentials : null //Return an object with the auth result
	},
	headers : { /* ... */ }, //Raw request headers
	method : 'string', //HTTP request method (like: GET, POST, PATCH)
	path : 'string', //Request path
	query : {}, //Parsed query string parameters as an object
	params : {}, //Parsed path parameters
	payload : {}, //Form content sent using POST, PUT or PATCH
	raw : null //Any raw form payload
}

request: multipart/form-data

v1.2.0+

When a request is made with the header Content-Type equals to multipart/form-data, and there's a file uploaded, the router will parse the request and convert it into a Buffer.

Let's use the following request example:

curl --location --request POST 'https://yourapi.com/upload' \
--form 'my_image=@"/home/user/screenshot.png"' \
--form 'my_field="Hello!"'

Where the request is sending a my_image with a image file, and my_field with a text field.

On request.payload you will get:

{
  "my_image": {
    "type": "file",
    "filename": "screenshot.png",
    "contentType": "image/png",
    "content": <Buffer 89 50 4e 47 0d 0a 1a 0a 00 ... 4406 more bytes>
  },
  "my_field": "Hello!"
}

The router will also parse the field names into objects, as:

curl --location --request POST 'https://yourapi.com/upload' \
--form 'my_field[a]=@"/home/user/list.csv"' \
--form 'my_field[b]="Hello!"'

Will be converted to:

{
  "my_field": {
    "a": {
      "type": "file",
      "filename": "list.csv",
      "contentType": "text/csv",
      "content": <Buffer 74 65 73 74 0a>
    },
    "b": "Hello!"
  }
}

reply

The reply parameter is an option to parse and manipulate the handler's response.

server.route({
	method: 'GET',
	path: '/hello',
	handler: async (request, reply) => {
		return reply.response('Hello world');
	}
});
/*
{
	"statusCode": 200,
	"response": "Hello world"
}
*/

All methods are chained, so they can be used in any order.


response(body: any)

mandatory

Set the response content. It can be any type of data. By default the content will be encapsulated in the response interface and converted using JSON.stringify(), unless the raw() method is used.

Example:

return reply.response('Hello world');
// { "statusCode": 200, "response": "Hello world" }
return reply.response(401);
// { "statusCode": 200, "response": 401 }
return reply.response(new Date());
// { "statusCode": 200, "response": "2020-01-01T00:00:00.000Z" }
return reply.response({ test : { a : true } });
// { "statusCode": 200, "response": { "test" : { "a" : true } } }
return reply.response([ 1, 2, 3 ]);
// { "statusCode": 200, "response": [ 1, 2, 3 ] }

raw()

optional v1.0.5+

Prevent the content to be encapsulated in the response interface, the content will still be converted using JSON.stringify(). It can e used before or after the response().

Example:

return reply.raw().response({ test : true });
// { "test" : true }
return reply.response({ test : true }).raw();
// { "test" : true }

code(statusCode: number)

optional

Set the status code for the response header and content. Useful to indicate errors and validations.

Default value: 200

Behavior:

A 200 code will create a response:

return reply.code(200).response('Hello world');
// { "statusCode": 200, "response": "Hello world" }

A code number greater or equal 400 will be be treated has an error, and will generate an HTTP error code message related to the code number:

return reply.code(404).response('Hello world');
// { "statusCode": 404, "error": "Not Found", "message": "Hello world" }
return reply.code(412).response('Hello world');
// { "statusCode": 412, "error": "Precondition Failed", "message": "Hello world" }
return reply.code(416).response('Hello world');
// { "statusCode": 416, "error": "Range Not Satisfiable", "message": "Hello world" }
return reply.code(417).response('Hello world');
// { "statusCode": 417, "error": "Expectation Failed", "message": "Hello world" }

type(contentType: string)

optional

Set a different content type for the response. Useful to render HTML, CSV, or plain text pages.

Default value: application/json

return reply.type('text/html').raw().response('<html><h1>Hello world</h1></html>');

header(key: string, value: string)

optional

Set custom response headers.

return reply.header('x-key', 'abcdef').response('Hello world');

meta(key: string, value: any)

optional v1.0.14+

Adds extra keys to the response object.

Note: This option will not be renders if you use with reply.raw() or server.options.wrapResponse = false.

return reply.response('Hello world').extra('link', 'www.com');
// { "statusCode": 200, "response": "Hello world", "link": "www.com" }
return reply.response('Hello world').extra('self', true);
// { "statusCode": 200, "response": "Hello world", "self": true }
return reply.response('Hello world').extra('page', { current: 1 });
// { "statusCode": 200, "response": "Hello world", "page": { "current": 1 } }
return reply.response('Hello world').extra('related', [1, 2, 3]);
// { "statusCode": 200, "response": "Hello world", "related": [1, 2, 3] }
return reply.response('Hello world').extra('page', { current: 1 }).extra('self', true);
// { "statusCode": 200, "response": "Hello world", "page": { "current": 1 }, "self": true }

redirect(url: string, <statusCode: number>)

optional v1.0.11+

Redirect the user to a specific URL. Status Code is optional, and will be set to 302 if no other is provided;

Example:

return reply.redirect('https://www.site.com'); //302 Found
return reply.redirect('https://www.site.com', 301); //301 Moved Permanently

This method is equivalent to:

return reply.raw().response(null).code(302).header('Location', 'https://www.site.com');