The API Gateway does a lot of things for you and in particular provides a default error handling behaviour that assumes that a successful result should map to a HTTP response with status code 200: OK
and an error result should map to a response with status code 400: Bad Request
. This works for simple use cases but when building a complex API, you may want to have more control over what is returned. Some of the things you may want to do include:
The API Gateway allows you to do this by specifying the HTTP response type on individual API endpoints. Doing this gives you more control by removing the default behaviour of the API Gateway but this means that you also need to adapt what your actions return to tell the API Gateway what do do.
This example is a variation of the “Hello World” API Gateway example that shows the changes that need to apply:
packages: hello_world_package: version: 1.0 license: Apache-2.0 actions: hello_world: function: src/hello_http.js web-export: true apis: hello-world: hello: world: hello_world: method: GET response: http
There are two key changes to this file:
response
field with value http
was added to the API,hello_world
action points to a different file detailed below.function main(params) { if(params.name && params.place) { return { body: { greeting: `Hello ${params.name} from ${params.place}` }, statusCode: 200, headers: {'Content-Type': 'application/json'} }; } else { return { error: { body: { message: 'Attributes name and place are mandatory' }, statusCode: 400, headers: {'Content-Type': 'application/json'} } } } }
Because a HTTP response disables the API Gateway default handling, you have to provide a more complex response that fills in the blanks and provides:
statusCode
field with the required HTTP status code,body
field that contains your normal payload,headers
field that includes any HTTP header you want to set, typically Content-Type
.If you don‘t provide this structure, the API Gateway will generate a HTTP response with status code 204: No Content
and an empty body. If this occurs when it shouldn’t, it‘s probably a sign that you have a HTTP response specified with the gateway but the underlying action doesn’t return this structure.
When you want to return an error, you need to provide the same structure wrapped into an error
object. If you don't wrap it into an error
object, it will still work from an HTTP perspective but OpenWhisk will not recognise it as an error.
This structure will work with any language that is supported by OpenWhisk, such as python or Java. If you are using JavaScript, you can make use of Promise.resolve
and Promise.reject
to make your code more readable by removing the need for the error
wrapper:
function main(params) { if(params.name && params.place) { return Promise.resolve({ body: { greeting: `Hello ${params.name} from ${params.place}` }, statusCode: 200, headers: {'Content-Type': 'application/json'} }); } else { return Promise.reject({ body: { message: 'Attributes name and place are mandatory' }, statusCode: 400, headers: {'Content-Type': 'application/json'} }); } }
You can actually deploy the “API Gateway HTTP” manifest from the openwhisk-wskdeploy project directory if you have downloaded it from GitHub:
$ wskdeploy -m docs/examples/manifest_hello_world_apigateway_http.yaml
Check the full URL of your API first:
$ wsk api list
This will return some information on the API, including the full URL, which should end with hello/world
. It can then be invoked:
$ curl -i <url>
The invocation should return a JSON response with status code 400
that includes this result:
{ "message": "Attributes name and place are mandatory" }
This shows our error handling code working. To get a valid response, we need to provide the name
and place
parameters:
$ curl -i <url>?name=World&place=Earth
You should then see a JSON response with status code 200
and the following result:
{ "greeting": "Hello World from Earth!" }
This example shows how you can have full control over the HTTP response produced by the API Gateway. This is essential when building a good REST API. Taking this example further, you can also return different payloads, such as CSV or XML files.
The source code for the manifest and JavaScript files can be found here:
For convenience, the Packages and Actions grammar can be found here: