An instance of the Claudia API Builder should be used as the module export from your API module. You can create a new API simply
by instantiating a new ApiBuilder, then defining HTTP handlers for paths by calling .get, .put, and .post. For example, the following
snippet creates a single handler for a GET call to /greet, responding with a parameterised message:
var ApiBuilder = require('claudia-api-builder'),
api = new ApiBuilder(),
superb = require('superb');
module.exports = api;
api.get('/greet', function (request) {
return request.queryString.name + ' is ' + superb();
});For a more detailed example, see the Web API Example project.
Claudia will automatically bundle all the parameters and pass it to your handler, so you do not have to define request and response models. The request object passed to your handler contains the following properties:
queryString: a key-value map of query string argumentsenv: a key-value map of the API Gateway stage variables (useful for storing resource identifiers and access keys)headers: a key-value map of all the HTTP headers posted by the client (header names have the same case as in the request)normalizedHeaders: (sinceclaudia 1.6.0) a key-value map of all the HTTP headers posted by the client (header names are lowercased for easier processing)post: in case of a FORM post (application/x-form-www-urlencoded), a key-value map of the values postedbody: in case of anapplication/json, the body of the request, parsed as a JSON object; in case ofapplication/xmlortext/plainPOST or PUT, the body of the request as a stringrawBody: (sinceclaudia 1.6.0, only when content type isapplication/json) the unparsed body of the request as a stringpathParams: arguments from dynamic path parameter mappings (such as '/people/{name}')lambdaContext: (sinceclaudia-api-builder 1.3.0) the Lambda Context object for the active requestcontext: a key-value map of elements from the API Gateway context, see the $context variable documentation for more info on individual fieldsmethod: HTTP invocation methodpath: the active resource path (will include generic path components, eg /people/{name})stage: API Gateway stagesourceIp: Source IPaccountId: identity account IDuser: user identity from the contextuserAgent: user agent from the API Gateway contextuserArn: user ARN from the API Gateway contextcaller: caller identityapiKey: API key used for the callauthorizerPrincipalIdcognitoAuthenticationProvidercognitoAuthenticationTypecognitoIdentityIdcognitoIdentityPoolId
You can either respond synchronously (just return a value, as above), or respond with a Promise. In that case, the lambda function will wait until the
Promise resolves or rejects before responding. API Builder just checks for the .then method, so it should work with any A+ Promise library.
To implement a custom termination workflow, use the request.lambdaContext object, and return a Promise that never gets resolved.
By default, Claudia.js uses 500 as the HTTP response code for all errors, and 200 for successful operations. The application/json content type is default for both successes and failures. You can change all that by using the optional third argument to handler definition methods. All keys are optional, and the structure is:
error: a number or a key-value map. If a number is specified, it will be used as the HTTP response code. If a key-value map is specified, it should have the following keys:code: HTTP response codecontentType: the content type of the responseheaders: a key-value map of hard-coded header values, or an array enumerating custom header names. See Custom headers below for more information
success: a number or a key-value map. If a number is specified, it will be used as the HTTP response code. If a key-value map is specified, it should have the following keys:code: HTTP response codecontentType: the content type of the responseheaders: a key-value map of hard-coded header values, or an array enumerating custom header names. See Custom headers below for more information
apiKeyRequired: boolean, determines if a valid API key is required to call this method. See Requiring Api Keys below for more information
For example:
api.get('/greet', function (request) {
return request.queryString.name + ' is ' + superb();
}, {
success: { contentType: 'text/plain' },
error: {code: 403}
});These special rules apply to content types and codes:
- When the error content type is
text/plainortext/html, only the error message is sent back in the body, not the entire error structure. - When the error content type is
application/json, the entire error structure is sent back with the response. - When the response type is
application/json, the response is JSON-encoded. So if you just send back a string, it will have quotes around it. - When the response type is
text/plain,text/xml,text/htmlorapplication/xml, the response is sent back without JSON encoding (so no extra quotes). - In case of 3xx response codes for success, the response goes into the
Locationheader, so you can easily create HTTP redirects.
To see these options in action, see the Serving HTML Example project.
Claudia API Builder provides limited support for custom HTTP headers. AWS API Gateway requires all custom headers to be enumerated upfront, and you can use the success.headers and error.headers keys of your handler configuration for that. There are two options for enumerating headers:
- Hard-code header values in the configuration (useful for ending sessions in case of errors, redirecting to a well-known location after log-outs etc). To do this, list headers as key-value pairs. For example:
api.get('/hard-coded-headers', function () {
return 'OK';
}, {success: {headers: {'X-Version': '101', 'Content-Type': 'text/plain'}}});- Dynamically assign header values from your API code. To do this, evaluate header names as an array, then return an instance of
ApiResponse(contents, headers)from your handler method. For example:
api.get('/programmatic-headers', function () {
return new api.ApiResponse('OK', {'X-Version': '202', 'Content-Type': 'text/plain'});
}, {success: {headers: ['X-Version', 'Content-Type']}});Due to the limitations with Lambda error processing, the error.headers key can only be hard-coded. Dynamic values for error handlers are not supported.
To see custom headers in action, see the Custom Headers Example Project.
Claudia API builder automatically sets up the API to allow cross-origin resource sharing (CORS). The most common usage scenario for API Gateway projects is to provide dynamic functions to Web sites served on a different domain, so CORS is necessary to support that use case. To simplify things, by default, APIs allow calls from any domain.
If you plan to proxy both the main web site and the APIs through a CDN and put them under a single domain, or if you want to restrict access to your APIs, you can override the default behaviour for CORS handling.
To completely prevent CORS access, use:
api.corsOrigin(false)To hard-code the CORS origin to a particular domain, call the corsOrigin function with a string, representing the target origin:
api.corsOrigin('https://www.claudiajs.com')To dynamically choose an origin (for example to support different configurations for development and production use, or to allow multiple sub-domains to access your API), call pass a JavaScript function into corsOrigin. Your function will receive the request object (filled with stage variables and the requesting headers) and should return a string with the contents of the origin header. This has to be a synchronous function (promises are not supported).
api.corsOrigin(function (request) {
if (/claudiajs.com$/.test(request.headers.Origin)) {
return request.headers.Origin;
}
return '';
});If your API endpoints use HTTP headers as parameters, you may need to allow additional headers in Access-Control-Allow-Headers. To do so, just call the corsHeaders method on the API, and pass a string with the Allow-Header value.
api.corsHeaders('Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Api-Version');To see this in action, see the Custom CORS Example Project. For more information on CORS, see the MDN CORS page.
There are two common ways for passing configuration variables to your API:
- Store configuration into AWS API Gateway Stage Variables. This is a good option for alphanumeric keys and short configuration items. Different Lambda versions (development, testing, production) will automatically get the correct values through the
request.envobject. - Store configuration into a file deployed with the function, and then detect which file to load by using
request.context.stage.
since 1.4.0
If your API depends on configuration in stage variables, you can automate the configuration process during deployment. Claudia will then enable users to configure the variable value either from the command line, or by prompting interactively during deployment. The syntax is:
api.addPostDeployConfig(stageVarName, prompt, configOption);stageVarName:string– the name of the stage variable you want to configure. To stay safe, use alphanumeric characters only, API Gateway does not allow special characters in variable namesprompt:string– the text to display when prompting the users to interactively enter the variableconfigOption:string– the name of the command-line option that will be used as a flag for the configuration process.
If the configuration option is provided as a string, the value is automatically sent to AWS for the current stage without prompting. If the configuration option is provided without value, API Builder will ask the users to interactively enter it. Here's an example:
api.addPostDeployConfig('message', 'Enter a message:', 'custom-message');In this case, message is the name of the stage variable (it will be available as request.env.message later). Enter a message: is the prompt that the users will see during deployment, and custom-message is the configuration option required to trigger the step. When an API contains that line, you can make Claudia ask you to define the stage variable by running
claudia update --custom-messageLikewise, you can provide the value directly in the command line for unattended operation
claudia update --custom-message PingTo see this in action, see the Post-deploy configuration example project.
Note that the sequence of post-deployment steps is not guaranteed. Create isolated steps, don't assume any particular order between them.
If you need to configure the API automatically (for example execute calls to third parties to set up webhooks and so on), add a post-deploy step to your API. The syntax is:
api.addPostDeployStep(stepName, function (commandLineOptions, lambdaProperties, utils) {} )stepName:string– a unique post-deploy step name, that will be used to report results.commandLineOptions:object– key-value pairs of options passed to Claudia from the command line. Use this to detect, for example, if the user required re-configuring the API, or to pass parameters to the configuration function from the command linelambdaProperties:object– contains the following keysname:string– the lambda function namealias:string– the active lambda version alias. Use this as the stage name if you want to configure stage variablesapiId:string– the API Gateway API IDapiUrl:string– the root URL of the API, accessible from the webregion:string– the AWS Region where the Lambda and API are deployed
utils:object– key-value hash containing utility objects that you can use to simplify common tasks without introducing additional dependencies to your API projectPromise: the A+ Promise implementation used by Claudiaaws: the AWS SDK object, initialised with the login details of the current user (note that the JavaScript API does not initialise the Region property by default, so you may need to pass that to an individual service when you use it).apiGatewayPromise: a promisified version of the ApiGateway SDK (so instead ofcreateDeploymentthat requires a callback, you can usecreateDeploymentPromisethat returns aPromise). This object also takes care of AWS rate limits and automatically retries in case ofTooManyRequestsexceptions, so if you want to execute API gateway configuration calls from the post-deploy step, it's generally better to use this object instead of creating your own service instance.
The post-deploy step method can return a string or an object, or a Promise returning a string or an object. If it returns a Promise, the deployment will pause until the Promise resolves. In case of multiple post-deployment steps, they get executed in sequence, not concurrently. Any values returned from the method, or resolved by the Promise, will be included in the final installation report presented to the users. So you can take advantage of this, for example, to provide configuration information for third-party components that users need to set up manually.
Note that the sequence of post-deployment steps is not guaranteed. Create isolated steps, don't assume any particular order between them.
To see this in action, see the Post-deploy example project.
You can force a method to require an API key by using an optional third argument to handler definition methods, and setting the apiKeyRequired property on it. For example:
api.get('/echo', function (request) { ... }, {apiKeyRequired: true});See How to Use an API Key in API Gateway for more information on creating and using API keys.
since claudia 1.4.5
APIs by default do not require user level authorization, to enable browsers to call them. API Gateway also allows you to set fine-grained permissions based on IAM policies. To do that, configure the request processor by adding an authorizationType field, with the value of AWS_IAM – here's an example:
api.get('/hello', function (request) {...}, {authorizationType: 'AWS_IAM'} );See the Permissions Documentation Page of the API Gateway developer guide for information on how to set up user policies for authorization.
since claudia 1.5.0
By default, API Gateway requests will execute under the credentials of the user who created them. You can make the API execute under the credentials of a particular user/IAM role, or pass the caller credentials to the underlying Lambda function by setting the invokeWithCredentials flag. Set it to a IAM ARN to use a particular set of credentials, or to true to pass caller credentials. If you use this flag, the authorizationType is automatically set to AWS_IAM, so you don't need to specify it separately.
// use caller credentials
api.get('/hello', function (request) {...}, {invokeWithCredentials: true} );
// use specific credentials
api.get('/hello', function (request) {...}, {invokeWithCredentials: 'arn:aws:iam::123456789012:role/apigAwsProxyRole'} );since 1.5.0
API builder allows you to intercept requests and filter or modify them before proceeding with the normal routing process. To do that, call the intercept method
api.intercept(function (event) { ... });The following rules apply for intercepting requests:
- stop without executing the request, but don't cause an error: return a falsy value, or a promise resolving to a falsy value
- stop without executing the request, but with an error: throw an exception, or return a promise that rejects
- execute the original request: return the original event, or a promise resolving with the original event
- execute a modified request: return the modified event, or a promise resolving with the modified event
Check out the Intercepting Requests Example to see this in action.
since 1.4.0
API Builder expects the events to come in a particular format, when invoked via API Gateway. You can invoke the Lambda function built using API Builder directly, or set it up to receive events from other sources, by creating a handler for unsupported event types. The syntax is:
api.unsupportedEvent(callback);callback:function– a Lambda handler function
Note that the callback function completely takes over the responsibility for ending the Lambda context in this case. API Builder does not provide any shortcuts for Promises or any other features apart from directly passing the event and the context to the unsupported event handler.