This is a base project to bootstrap and prototype quickly. It is useful as a starting point for REST APIs and includes full OAuth 2.0 implementation as well as basic endpoints to create and update a user, health check endpoint, Facebook integration, migrations and a ready to rumble Dockerfile.
It relies on Postgres
for database and etcd
for configuration but both are easily customizable. An ORM library is used for database communication.
The API is using REST architectural style which means resources are access and modified via HTTP methods:
GET
(to get a resource or paginate over resource sets)POST
(to create new resources)PUT
(to update resources)DELETE
(to delete resources)
PATCH
might be implemented later in order to enable partial updates of resources (see the RFC).
The REST API objects are formatted according to JSON HAL specification. This means that each object has its own hyperlink clients can use to access it. Other related objects can be embedded into the response as well.
Simple example of JSON HAL resource:
{
"_links": {
"self": {
"href": "/v1/users/1"
}
},
"id": 1,
"email": "john@reese",
"created_at": "2015-12-17T06:17:54Z",
"updated_at": "2015-12-17T06:17:54Z"
}
Let's take a look at how a related object would be represented. The example bellow shows a file resource with embedded user object.
{
"_links": {
"self": {
"href":"/v1/files/1"
}
},
"_embedded": {
"user": {
"_links": {
"self": {
"href":"/v1/users/1"
}
},
"id":1
}
},
"id":1,
"user_id":1
}
Pagination example:
{
"_links":{
"first":{
"href":"/v1/files?page=1"
},
"last":{
"href":"/v1/files?page=2"
},
"next":{
"href":"/v1/files?page=2"
},
"prev":{
"href":""
},
"self":{
"href":"/v1/files?page=1"
}
},
"_embedded":{
"files":[
{
"_links":{
"self":{
"href":"/v1/files/1"
}
},
"id":1
},
{
"_links":{
"self":{
"href":"/v1/files/2"
}
},
"id":2
}
]
},
"count":2,
"page":1
}
According to Go 1.5 Vendor experiment, all dependencies are stored in the vendor directory. This approach is called vendoring
and is the best practice for Go projects to lock versions of dependencies in order to achieve reproducible builds.
This project uses dep for dependency management. To update dependencies during development:
dep ensure
If you are developing on OSX, install etcd
and Postgres
:
brew install etcd
Load a development configuration into etcd
:
etcdctl put /config/example_api.json '{
"Database": {
"Type": "postgres",
"Host": "localhost",
"Port": 5432,
"User": "example_api",
"Password": "",
"DatabaseName": "example_api",
"MaxIdleConns": 5,
"MaxOpenConns": 5
},
"Oauth": {
"AccessTokenLifetime": 3600,
"RefreshTokenLifetime": 1209600,
"AuthCodeLifetime": 3600
},
"Mailgun": {
"Domain": "example.com",
"APIKey": "mailgun_api_key",
"PublicAPIKey": "mailgun_private_api_key"
},
"Web": {
"Scheme": "http",
"Host": "localhost:8080",
"AppScheme": "http",
"AppHost": "localhost:8000"
},
"AppSpecific": {
"ConfirmationLifetime": 604800,
"InvitationLifetime": 604800,
"PasswordResetLifetime": 604800,
"CompanyName": "Example Ltd",
"CompanyNoreplyEmail": "[email protected]",
"ConfirmationURLFormat": "%s://%s/confirm-email/%s",
"InvitationURLFormat": "%s://%s/confirm-invitation/%s",
"PasswordResetURLFormat": "%s://%s/reset-password/%s"
},
"IsDevelopment": true
}'
Check the config was loaded properly:
etcdctl get /config/example_api.json
brew install postgres
You might want to create a Postgres
database:
createuser --createdb example_api
createdb -U example_api example_api
Compile the app:
go install .
Run migrations:
example-api migrate
And finally, run the app:
example-api runserver
When deploying, you can set etcd related environment variables:
ETCD_ENDPOINTS
ETCD_CERT_FILE
ETCD_KEY_FILE
ETCD_CA_FILE
ETCD_CONFIG_PATH
You might want to insert some test data if you are testing locally using curl
examples from this README:
example-api loaddata \
services/oauth/fixtures/scopes.yml \
services/oauth/fixtures/roles.yml \
services/oauth/fixtures/test_clients.yml \
services/oauth/fixtures/test_users.yml \
services/accounts/fixtures/test_users.yml
I have used a mix of unit and functional tests so you need to have sqlite
installed in order for the tests to run successfully as the suite creates an in-memory database.
To run tests:
make test
Build a Docker image and run the app in a container:
docker build -t example-api:latest .
docker run -e ETCD_ENDPOINTs=localhost:2379 -p 8080:8080 --name example-api example-api:latest
You can load fixtures with docker exec
command:
docker exec <container_id> /go/bin/example-api loaddata \
services/oauth/fixtures/scopes.yml \
services/oauth/fixtures/roles.yml \
services/oauth/fixtures/test_clients.yml
You can also execute interactive commands by passing -i
flag:
docker exec -i <container_id> /go/bin/example-api createoauthclient
docker exec -i <container_id> /go/bin/example-api createsuperuser
You can use docker-compose to start the app, postgres, etcd in separate linked containers:
docker-compose up
During docker-compose up
process all configuration and fixtures will be loaded. After successful up you can check, that app is running using for example the health check request:
curl --compressed -v localhost:8080/v1/health