A sample API implemented on top of go-chi and go-pg.
- modular code organization
- examples of standard CRUD operations
- environment dependent configuration (
.env
file) - authentication using JSON Web Tokens
- request validation
- query and request logs
- route/struct binding using middleware
- autogenerated slugs using BeforeInsert/BeforeUpdate hooks
- soft deletes
- migrations
- integration tests
- modd - recompiles and runs the
api
package in response to filesystem changes - Docker support
go run migrate/*.go
go run api/*.go
(or modd
)
go test ./...
The project can be launched and deployed using Docker containers with the help of docker-compose
. In development mode the source is mounted in a volume (the root project directory is mapped to /src
within the container). The production container is optimised to be as small as possible and contains compiled binaries (in the /srv
directory within the container) that allow to start the server / run migrations.
Build and start the project:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml build
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
Migrate the database:
docker exec -it go_notes_development go run migrate/*.go init
docker exec -it go_notes_development go run migrate/*.go
Run tests:
docker exec -it go_notes_development go test ./...
Build and start the project:
docker-compose -f docker-compose.yml -f docker-compose.prod.yml build
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
Migrate the database:
docker exec -it go_notes_production ./migrate init
docker exec -it go_notes_production ./migrate
You can access PostgreSQL database by connecting to localhost:5432 from the host machine (using Postico or other client). The port is mapped to 5432 by default. The port can be changed by updating the POSTGRES_DB_HOST_PORT
env variable.
Unauthorized request
curl http://localhost:8080/v1/note/
{
"status": "Unauthorized",
"error": "Invalid token."
}
Register a user account
curl --data '{"email":"[email protected]","password":"12345678","first_name":"Caroline","last_name":"Dennis"}' http://localhost:8080/auth/register
{
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJpZCI6N30.01ClhXk_k2E2ozMTeix-oRYhsTsHL2KtGYh3NUBDH4c"
}
Create a note
curl --data '{"Title":"This is a note","Content":"Content..."}' --header 'Authorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJpZCI6N30.01ClhXk_k2E2ozMTeix-oRYhsTsHL2KtGYh3NUBDH4c' http://localhost:8080/v1/note/
{
"id": 1,
"slug": "this-is-a-note",
"title": "This is a note",
"content": "Content...",
"updated_at": "2019-09-03T09:59:48.516568+02:00"
}
Update a note
curl -X PUT --data '{"Title":"This is an updated note","Content":"Content..."}' --header 'Authorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJpZCI6N30.01ClhXk_k2E2ozMTeix-oRYhsTsHL2KtGYh3NUBDH4c' http://localhost:8080/v1/note/1
{
"id": 1,
"slug": "this-is-an-updated-note",
"title": "This is an updated note",
"content": "Content...",
"updated_at": "2019-09-03T10:01:12.625071+02:00"
}
List notes
curl --header 'Authorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJpZCI6N30.01ClhXk_k2E2ozMTeix-oRYhsTsHL2KtGYh3NUBDH4c' http://localhost:8080/v1/note/
[
{
"id": 1,
"slug": "this-is-an-updated-note",
"title": "This is an updated note",
"content": "Content...",
"updated_at": "2019-09-03T10:01:12.625071+02:00"
}
]
Delete a note
curl -X DELETE --header 'Authorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAdGVzdC5jb20iLCJpZCI6N30.01ClhXk_k2E2ozMTeix-oRYhsTsHL2KtGYh3NUBDH4c' http://localhost:8080/v1/note/1
{
"status": "Success"
}