A base API project to bootstrap and prototype quickly.
Go HTML Shell Other
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
cmd Moved all service level packages into services package to make top le… Mar 28, 2017
config Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
database Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
docs Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
log Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
models Big refactoring. Removed Account model as it's an overkill. Mar 28, 2017
services Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
test-util Fixed linter issue. Oct 11, 2017
util Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
vendor Updated dependencies. Dec 20, 2017
.dockerignore Removed Makefile from .dockerignore May 24, 2017
.gitignore Fixing coverage report to aggregate results from all packages. Jul 14, 2017
.travis.yml Update .travis.yml Dec 19, 2017
Dockerfile Improved docker-compose. More reliable and resilient. Apr 30, 2017
Dockerfile-etcd-config Migrated to etcd API v3. Nov 30, 2016
Dockerfile.test Run tests with coverage in Dockerfile.test Oct 11, 2017
Gopkg.lock Updated dependencies. Dec 20, 2017
Gopkg.toml Updated dependencies. Dec 20, 2017
LICENSE Initial commit Feb 4, 2016
Makefile Increased gometalinter deadline. Dec 20, 2017
README.md Update README.md May 26, 2018
build-release.sh Improving build script. Jul 30, 2016
cut-release.sh Small refactoring. Jul 11, 2016
docker-compose.test.yml Refactoring of tests to run via docker-compose. Fixed introspect bug. Oct 11, 2017
docker-compose.yml Improved docker-compose. More reliable and resilient. Apr 30, 2017
docker-entrypoint.sh Improved docker-compose. More reliable and resilient. Apr 30, 2017
docker-etcd-config-entrypoint.sh Improved docker-compose. More reliable and resilient. Apr 30, 2017
example-api.go Big refactoring. Removed Account model as it's an overkill. Mar 28, 2017
gometalinter.json Create gometalinter.json Dec 19, 2017

README.md

Example API

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.

Travis Status for RichardKnop/example-api godoc for RichardKnop/example-api codecov for RichardKnop/example-api


API Design

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
}

Dependencies

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

Setup

If you are developing on OSX, install etcd and Postgres:

etcd

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": "noreply@example.com",
    "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

Postgres

brew install postgres

You might want to create a Postgres database:

createuser --createdb example_api
createdb -U example_api example_api

Compile & Run

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

Test Data

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

Testing

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

Docker

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

Docker Compose

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