accountapi-client
Example Client for an account API in golang withBDD
Description
In summary it is a go
client for the accounts API specified here.
This is the first time I've written any commercial grade code in golang... I'm also used to paired/mob programming so this has been a fun and useful learning exercise.
Quick Start
After cloning the repository and changing your working directory to that folder, the complete tests suite of unit tests and integration tests (BDD-style) can be run using either:
docker-compose up
or
make start
Usage
In you own application
This package is designed to be used in another go
application,
to this end there is an example.go in the root of the folder.
This can be build and run as is designed to be used as a reference implementation.
The code below, shows the minimum code required to create the client. The accountclient
package also exposes a New()
method to allow the client to use a custom logger that uses the ClientLogger interface and a custom repository that uses Repository interface. In the implementation below it uses the NewRestClient()
method to create the default REST implementation of the client.
package main
import (
"log"
"github.com/diversemix/accountapi-client/accountclient"
)
func main() {
logger := log.New(log.Writer(), "[client] ", log.Flags())
client := accountclient.NewRestClient(logger, "http://localhost:8080")
}
During Development
The Makefile has been designed to help development. Running the command make
will list all the commands and a brief description as a reminder. They are explained in detail below:
make start
- This is equivalent todocker-compose up
, but with the added step of stopping any currently running services beforehand. Therefore this is recommended over using docker-compose directly.make start-services
- This just starts the supporting services for running the BDD tests. Handy to leave these running when you are developing the BDD tests.make stop
- This will stop any running containers that are managed by the docker-compose file.make bdd-tests
- This runs the integration tests, it depends on having the supporting services running and the environment variableURL_UNDER_TEST
set to the accounts service you are testing, typicallyhttp://localhost:8080
make unit-tests
- This runs the unit tests, it has no dependents and is designed to run quickly to allow "failing fast" as a part of normal development.make test
- This runs all the tests and so has the same requirements as thebdd-tests
command. This is used as the start up command for testing container in docker-compose.
I've also found installing looper has been beneficial during development.
go get -u github.com/nathany/looper
Approach
Issues
-
Initially it was found that the container
accountapi
could not connect to the database. It was found there was a startup script missing - this was added inscripts/db/init.sql
*** -
Later it was found that the container
accountapi
sometimes panicked on startup. To avoid this happening, I extracted theentrypoint.sh
and modified it, this script is inscripts/new-entrypoint.sh
*** -
I have commented out the following scenarios - I would expect them to work but they do not. Maybe its my misunderstanding of how the server works?
# Scenario: Create an Account in GB without a Bic
# Given the country is "GB"
# And the Bic is ""
# Then the Account should be created in memory
# And the Account should not be created over the API
# Scenario: Create an Account in GB without a BankID
# Given the country is "GB"
# And the BankID is ""
# Then the Account should be created in memory
# And the Account should not be created over the API
Design Thinking
-
I was keen to ensure that the client that was to be created would be as idiomatic and easy to use for the developer consuming it. I started with the file
example.go
and have attempted to make it as easy to use as possible. Having learnt about BDD along the way, I can see the advantage of starting here - I am now a convert :) -
For the purposes of the "Single Responsibility Principle" the following
- RestRepository is responsible for all network transport (the only file using
net/http
) - entities/account.go is responsible for representing the entity that the API deals with. Validation has been used within this type given the documentation of the API. Again this is to fail fast so the validation can fail client-side before having to round-trip with all the network latency involved with that.
- data-mapper.go - is responsible for (un)marshalling the
Account
objects to/fromJSON
- this was a term borrowed from DDD, where effectively JSON is being used for the DTO. - client.go has the responsibility solely for orchestration between the
Interface
and theRepository
selected on creation.
- RestRepository is responsible for all network transport (the only file using
-
Interfaces, there are the following interfaces to use the SIP interface-segregation principle.
- ClientInterface - implemented by the main package "accountclient"
- ClientLogger - implemented by the standard "log" package, but abstracted for easy of testing.
- Response - implemented by
RestResponse
- Repository - implemented by
RestRepository
Testing Strategy
Normally I would ensure there are the three level of tests are complete before a product goes out the door. These are:
- Unit Tests
- Integration Tests
- End-to-End Tests
Without a staging environment or equivalent it is impossible to do (3). I have completed what I think is a good "first pass" at the unit tests for this interview - obviously I could carry on! In terms of integration tests, as we have the container available to us, I have attempted to do these in BDD style using godog. This is the first time I have used this technique, again would appreciate any feedback. Thanks!