This project represents a reasonable approximation of what I consider to be a toy-level production-ready golang microservice.
Since this project is time-boxed to one week, I was forced to make a few trade-offs in quality for time sake.
To call out a few things I would change:
-
Delegating validation to the
user
package is a bit backwards and creates some awkwardness around handling requests. Specifically, the "UpdateUser" handler anduser.Parse
. What I should be doing is providing a OpenAPI schema, and then validating the request itself against that. -
Speaking of OpenAPI, there are some excellent code generation tools that I would likely involve around request validation. oapi-codegen is widely used and could save writing some boilerplate around requests.
-
A lot of the tests should be converted to table-based tests for readability sake, especially the tests having to do with validating lists of missing properties.
-
Test code quality could be better in general. There is more copy-paste than I would prefer.
-
I would like to have added a docker-compose based local DynamoDB development option, with a local smoke test running against the actual application.
-
I would like to run all commands in the
Makefile
with a docker container for portability.
Below is the TODO list I used while developing the project:
TODO:
- [WONT] Set up the serverless framework for local testing, etc.
- [DONE] Should deploy with Serverless deploy
- [DONE] Spin up DynamoDB
- [DONE] Enable the addition of a new user with fields like userid, email. name, DOB, etc.
- [DONE] Fetch user information based on UserID
- [DONE] Modify existing user details using UserID
- [DONE] Remove a user record based on UserID
- [DONE] /users (POST) to add a new user
- [DONE] /users/ GET to retrieve details of the user
- [DONE] PUT
- [DONE] DELETE
- [DONE] Error handling with descriptive error code and message
- [WONT] Run all commands in docker container
- [WONT] Local integration tests
- [WONT] Add test to ensure client is working
- [WONT] Interesting decisions section for readme
- [DONE] Update date fields to strings instead of time objects
- [DONE] move repo functions into own files
- [DONE] add proper check for existing user with email
- [DONE] Fix put request to behave a bit better
This application requires a linux or Unix system to function.
On windows I highly recommend the WSL2 linux emulation functionality.
To get started, you will need the following applications installed:
- Serverless
- Docker
- GoLang
- Make is likely already on your system.
I will leave configuring and installing these applications as an exercise for the reader.
Commands for this project are centralized in a Makefile.
make build
Build iterates through the ./handlers
folder and runs go build
on each of them.
This generates the binaries the serverless lambdas will execute when processing requests
make clean
Clean removes artifacts from previous builds, and prepares the environment for the next version.
make deploy
Deploy calls the clean and build makefile commands, and then uses the serverless framework to deploy the code to AWS.
make down
Down deletes the entire stack created by the deploy
command.
make fmt
This command runs go fmt ./...
and formats source code.
In the future we may wish to add additional formatters so we can format various file types with one command.
make test
This command runs the golang test suite.
make testv
This command runs the golang test suite in verbose mode
make gen
This command runs automated code generation for our golang repositories.
In the future we may wish to add a JSONSchema or documentation generation command.
make lint
This command runs golangci-lint against our source code.
I have implemented a Postman collection that contains example queries for each of our APIs. If you would like an easy way to iterate and explore this API, I recommend importing the collection.
To update the ID and apiURL, navigate to the root collection, and edit the Variables tab:
The API consists of a single REST endpoint that supports the following operations:
- GET /user/{id}
- POST /user
- PUT /user/{id}
- DELETE /user]{id}
This endpoint will operate as expected: If provided a valid ID, it will return a user object.
Otherwise, it will 404 or 500 based on the nature of the invalidity of the request.
This endpoint will create a new user.
It expects a POST request with a json payload of the following format:
{
"firstName": "Fred",
"lastName": "Flintstone",
"email": "fred@example.com", // Must be a valid email
"DOB": "2020-12-09T16:09:53+00:00" // Must be a valid ISO8601 datetime
}
This endpoint will update the user identified by the provided ID.
It expects a PUT request with a JSON payload of the following format:
{
"firstName": "Fred",
"lastName": "Flintstone",
"email": "fred@example.com",
"DOB": "2020-12-09T16:09:53+00:00"
}
This request will delete the resource with the provided ID.
To deploy this application, simply call make deploy
.
This will build and deploy the application.
Unit tests can be executed using the make test
command.
For manual testing, it is recommended you make deploy
to AWS, and get the API endpoint from the AWS console, and then use the provided postman collection to iterate on your changes.