There are a lot of materials about how to write services, where at first you need to choose some framework to use, then comes wiring of handlers, configs, logs, storage, etc, not to mention deploying that service somewhere. We’ve been writing services for quite some time and more often than not you’d just want to skip all this tedious process of gluing stuff together and just write some useful code. That’s why we created a tool, called Mify — it’s an open-source infrastructure boilerplate generator, which would help you build a service, taking the best practices used to date. So in this tutorial, we’ll show how to create a simple service using Mify with a classic example — a to-do app. Prerequisites Install 1.18+, Go Docker Get Mify from our GitHub: https://github.com/mify-io/mify Install or curl to test endpoints Postman Before starting this tutorial, here’s the link to the complete example: https://github.com/mify-io/todo-app-example Creating Project After installing Mify, to start the project you need to create the workspace: $ mify init todo-app $ cd todo-app After getting into the new workspace, run: $ mify add service todo-backend Now, this will create a Go template for your to-do backend. Here’s a simplified tree of the workspace with all generated files: . ├── go-services │ ├── cmd │ │ ├── dev-runner │ │ │ └── main.go │ │ └── todo-backend │ │ ├── Dockerfile │ │ └── main.go │ ├── go.mod │ ├── go.sum │ └── internal │ ├── pkg │ │ └── generated │ │ ├── configs │ │ │ └── ... │ │ ├── consul │ │ │ └── ... │ │ ├── logs │ │ │ └── ... │ │ └── metrics │ │ └── ... │ └── todo-backend │ ├── app │ │ ├── request_extra.go │ │ ├── router │ │ │ └── router.go │ │ └── service_extra.go │ └── generated │ ├── api | | └── ... │ ├── app │ │ └── ... │ ├── apputil │ │ └── ... │ └── core │ └── ... ├── schemas │ └── todo-backend │ ├── api │ │ └── api.yaml │ └── service.mify.yaml └── workspace.mify.yaml Mify loosely follows one of the common Go layouts, which is suitable for multiple services in one repository. In there are common libraries for configs, logs, and metrics that can be reused for multiple services. Your service go-to directory is in . internal/pkg/generated internal/todo-backend At this point this service is pretty bare, so we need to add API to it. Defining API You can find the OpenAPI schema for the todo-backend in file. Schemas directory in the root of the workspace is a place where all service configs related to Mify are stored. schemas/todo-backend/api/api.yaml Let’s create a simple CRUD API for your todo backend: for adding new to-do notes. POST /todos for updating, retrieving, and deleting them. PUT,GET,DELETE /todos/{id} Here’s how your OpenAPI schema would look for this API: https://gist.github.com/chebykinn/5dc7b30a2a57a1ab4584895131295e1f Replace the previous schema with this one and run . You can run it each time you update the schema and it will regenerate all the changed stuff. mify generate Building and Testing $ cd go-services $ go mod tidy $ go run ./cmd/todo-backend You should see startup logs like that: You can see the service port in log message, copy it to Postman, and try calling some API handler: starting api server You can see that the handler returned nothing, which is expected because as the error suggests, it’s not implemented yet. Adding Models and Mock Storage First, we need to create a model for the todo note, we’ll put it in the package domain in : go-services/internal/todo-backend/domain/todo.go https://gist.github.com/chebykinn/0c2905f07d76082bd9d63a56a720371c?embedable=true This is also a good place to define the interface for storage, which is useful for decoupling persistence logic from the application. In this tutorial, we’ll use mock storage, in memory, but Mify also supports Postgres, which we can add later in a follow-up article. Let’s put storage in go-services/internal/todo-backend/storage/todo_mem.go: https://gist.github.com/chebykinn/1769d6881e929bfb225fc203c48e1496?embedable=true That’s all for logic, we just need to add it to handlers. Implementing Handlers for POST method, and go-services/internal/todo-backend/handlers/todos/service.go for others. go-services/internal/todo-backend/handlers/todos/id/service.go Here’s an example of a stub of the POST method: https://gist.github.com/chebykinn/e49b483330ea7c84a1b8082b0a86fc01?embedable=true Now, let’s implement all handlers. : go-services/internal/todo-backend/handlers/todos/service.go https://gist.github.com/chebykinn/6f88c03680167c4dc286f1b6226341f9?embedable=true Don’t forget to update imports: import ( "net/http" "strconv" "example.com/namespace/todo-app/go-services/internal/todo-backend/domain" "example.com/namespace/todo-app/go-services/internal/todo-backend/generated/api" "example.com/namespace/todo-app/go-services/internal/todo-backend/generated/apputil" "example.com/namespace/todo-app/go-services/internal/todo-backend/generated/core" "example.com/namespace/todo-app/go-services/internal/todo-backend/handlers" ) : go-services/internal/todo-backend/handlers/todos/id/service.go https://gist.github.com/chebykinn/98d2d051671dfbefb464b1f59b159d15?embedable=true And here are imports for them as well: import ( "errors" "fmt" "net/http" "strconv" "example.com/namespace/todo-app/go-services/internal/todo-backend/domain" "example.com/namespace/todo-app/go-services/internal/todo-backend/generated/api" "example.com/namespace/todo-app/go-services/internal/todo-backend/generated/apputil" "example.com/namespace/todo-app/go-services/internal/todo-backend/generated/core" "example.com/namespace/todo-app/go-services/internal/todo-backend/handlers" "example.com/namespace/todo-app/go-services/internal/todo-backend/storage" ) The handler’s logic is pretty simple, we’re just converting generated OpenAPI models to our application one and back, and to avoid duplication in code, here’s a helper for creating a TodoNode response, which is used in these implementations: : go-services/internal/todo-backend/handlers/common.go https://gist.github.com/chebykinn/702f24abe035cd99dbc06c4447ecc755?embedable=true Testing Again First, we can add a new todo note with a POST request: Check if it is added with a GET request: Update it with a PUT request: Delete it: And run GET once again to check if it was deleted: What’s Next Persistent storage, like Postgres, Configuration, Authentication middleware, Deployment to the cloud. Most of this stuff is covered in our docs, so check them out: , but stay tuned for the next articles. https://mify.io/docs Also Published Here