Experimenting with Full Stack Development in Go — Part 2: Setting up the Backend
I first decided to bring up a backed on AWS which offered a Swagger defined REST API to a data model persisted in Dynamodb realized with Lambda functions.
This of, course, is well trodden ground and there are many reports on how to do similar things; there is no point in repeating here what is already known. I will however note a couple of specific observations relating to this design which were not obvious to me when I started:
- the AWS API Gateway offers nice supports for REST API implementation; a Swagger definition of the API can be provided and the endpoints are defined automatically. The implementation did have some issues with
example
fields in the data model — these fields had to be removed before the AWS Swagger parser could handle the API definition; - the Lambda integration offered two distinct modes one based on a proxying behaviour and one which didn’t. The proxying solution is more powerful and necessary in most sensible REST API implementations as it supports returning HTTP Status codes from the Lambda function. Interestingly, AWS performs consistency checking between Status codes returned by the Lambda function and those specified in the Swagger definition;
- while the AWS API Gateway REST mechanisms support straightforward Lambda integration, it is not necessary to have a strict one-to-one mapping between endpoints and Lambda functions. Indeed, one seemingly common scenario is that a single Lambda function handles multiple (or even all) requests for a given REST API and a router inside the Lambda function determines the behaviour of the Lambda function;
- it was necessary to configure CORS handling within the API — this could be configured in via the AWS console or it could be included in the definition of the Swagger API. The latter is the approach used in this work;
- The AWS SDK for Go worked fine, although documentation on this could be improved a little — some time was spent trying to understand the mapping between native go types and those handled by DynamoDB
The REST API uses HTTPS: using HTTP is not an option. AWS recently announced an alternative HTTP based mechanism within the API Gateway which is significantly cheaper. It is clearly less sophisticated than the REST implementation, eg not offering Swagger integrations, and for most serious applications HTTPS is probably not negotiable.
In the design here, I chose to use specific Lambda functions for each REST endpoint: it is not clear whether this is a good (or indeed sensible) design choice — it works fine in this case, but in larger applications, I guess more careful consideration of this is required.
As usual on AWS, some care must be taken when dealing with permissions — I configured a new role which has permissions to execute Lambda functions and perform DynamoDB operations; this was required when linking the API Gateway to the Lambda functions as well as when creating the Lambda functions.
I did not specifically use the serverless framework here as I wanted to understand more deeply what is going on under the hood. I guess this could have handled some of the API Gateway plumbing to make things easier.
Now on to the front end!