Development
This project is a template for implementing an API in a robust and
reliable way. It uses the echo web framework to serve the API and the
oapi-codegen tool to generate the API server from an OpenAPI document.
The build system uses bingo to manage build dependencies.
This project is self-contained in that it provides static web assets -
so you can run it and connect to http://127.1:10721/ to play around
with the API.
Project organisation
All generated code ends in .gen.go and is not committed.
-
api/ and internal/api - The OpenAPI document and the oapi-codegen
configs respectively. The generated code is split into the code for
endpoints (endpoints.gen.go) and the data types (models.gen.go).
-
mock/ and .mockery.yaml - The mockery generated code and its
configs respectively.
-
internal/storage - Implements a storage layer. When using this
template, you'd need to replace internal/storage/storage.go with
your own storage routines.
-
internal/server - Implements the server. The main thing to replace
here is internal/server/api.go with your own API implementation.
See the "Implementing the API" section below.
-
internal/static - A simple web UI for testing the API server.
Remove the references to it in internal/server/server.go to
disable it.
Makefile targets:
-
all - default target. It will run generate, test, lint and
build.
-
generate - runs any code generators. Preferably using
go generate. Generated go files should end in *.gen.go
and .gitignore is set to ignore them.
-
lint - runs linters.
-
test - runs tests.
-
build - runs the build.
-
cobra-cli - this can be used to run cobra-cli. The
CMD arg can be used to create new commands. Say you need db
migration. You can make a migrate command like so:
make cobra-cli CMD=migrate
Makefile targets for CI systems:
-
ci-all - this will run ci-generate, ci-test, ci-lint
and ci-build.
Artifacts: *.gen.go, reports/, bin/
-
ci-generate - same as generate.
Artifacts: *.gen.go
-
ci-lint - same as lint.
Artifacts: reports/
-
ci-test - same as test.
Artifacts: reports/
-
ci-build - same as buils.
Artifacts: bin/
Consistency
The project has a .editorconfig file to get consistency in edits.
A full build can be run with make and it will run go generate with the
correct env vars set, run tests and then do a build. Test results will be
thrown up in a browser tab. The tests include a run of golangci-lint
as well as yamllint on the OpenAPI document. Ideally folks using
this template would enable golangci-lint in their IDE/editor.
There's also a goal to limit the amount of code that needs to be written.
At the time of this writing around 25% of the code is written, 10% is
written test code and the rest is generated code.
CI Ready
All make targets have a ci- variant. These produce artifacts for code
quality and test results and test coverage in the reports/ directory.
Instrumentation
Using echo middleware, there are Prometheus metrics on endpoints.
There's also timing for storage calls. The latter would need to be
changed for an actual project, but the general idea is there.
Implementing the API
Delete the petstore implementation in internal/server/api.go leaving just the
API type and the NewAPI function. Modify them with the state they need.
Then start running make to learn what functions you need to implement.
$ make
go fmt ./...
go vet ./...
# gitlab.com/lyda/template-go-api/internal/server
internal/server/server.go:25:37: cannot use NewAPI(db) (value of type *API) as api.StrictServerInterface value in argument to api.NewStrictHandler: *API does not implement api.StrictServerInterface (missing method DeletePet)
make: *** [Makefile:32: test] Error 1
When implementing these, look in internal/api/endpoints.gen.go
for the types the functions need to accept and return. Look in
internal/api/models.gen.go for the types of the objects you're
storing/sending.
TODO
- Use the embedded OpenAPI document to verify requests and responses
as middleware.
- Generate the javascript library for this api.
- Make a fully json schema drive UI - maybe something other than alpaca?
- Implement tracing with OpenTelemetry.
- Have the UI exercise all API endpoints.
- Generate a fuzz tester to run against the server. Have a make target
to run the server and then run the fuzz tester against it.
- Implement CI configs for Gitlab and Github.
A special mention for a thing not to do:
- The least interesting thing to use an OpenAPI document for: generate
documentation.
Deployment
There are Makefile targets for generating a docker container and for
deploying to a local kind cluster. It can also create a kind cluster
with contour for ingress.
Makefile targets for deployment:
container - builds a container with docker.
create-kind-cluster - creates a kind cluster if one does not exist.
deploy-kind - deploys image to kind and deploys the application
to the kind cluster.
delete-kind-cluster - deletes the kind cluster.
Makefile targets for CI systems:
ci-container - uses kaniko to build a container. It might be
of interest to explore alternatives to kaniko: Buildah, podman,
buildkit and possibly others. For now kaniko works.
- deployment - no target for this because this will depend a huge amount
on your deployment system. Tools like ArgoCD, Gitlab or others can
manage deployment external to the code base.