todo

package module
v0.0.0-...-4b6ff60 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 20, 2026 License: MIT Imports: 11 Imported by: 0

README

"ToDo API" Microservice Example

codecov

Introduction

Welcome! 👋

This is an educational repository that includes a microservice written in Go. It is used as the principal example of my video series: Building Microservices in Go.

This repository is not a template nor a framework, it's a collection of patterns and guidelines I've successfully used to deliver enterprise microservices when using Go, and just like with everything in Software Development some trade-offs were made.

My end goal with this project is to help you learn another way to structure your Go project with 3 final goals:

  1. It is enterprise, meant to last for years,
  2. It allows a team to collaborate efficiently with little friction, and
  3. It is as idiomatic as possible.

Join the fun at https://youtube.com/MarioCarrion.

Domain Driven Design

This project uses a lot of the ideas introduced by Eric Evans in his book Domain Driven Design, I do encourage reading that book but before I think reading Domain-Driven Design Distilled makes more sense, also there's a free to download DDD Reference available as well.

On YouTube I created a playlist that includes some of my favorite talks and webinars, feel free to explore that as well.

Project Structure

Talking specifically about microservices only, the structure I like to recommend is the following, everything using < and > depends on the domain being implemented and the bounded context being defined.

  • dockerfiles/: defines all the Dockerfiles used by the different applications used in the project.
  • cmd/
    • <primary-server>/: uses primary database.
    • <replica-server>/: uses readonly databases.
    • <binaryN>/
  • db/
    • migrations/: contains database migrations.
    • seeds/: contains file meant to populate basic database values.
  • internal/: defines the core domain.
    • <datastoreN>/: a concrete repository used by the domain, for example postgresql
    • rest/: defines HTTP Handlers.
    • service/: orchestrates use cases and manages transactions.

There are cases where requiring a new bounded context is needed, in those cases the recommendation would be to define a package like internal/<bounded-context> that then should follow the same structure, for example:

  • internal/<bounded-context>/
    • internal/<bounded-context>/<datastoreN>
    • internal/<bounded-context>/http
    • internal/<bounded-context>/service

Tools

Please refer to the documentation in internal/tools/.

Features

Icons meaning:

  • YouTube video means a link to Youtube video.
  • Blog post means a link to Blog post.

In no particular order:

More ideas

Running project locally using Docker Compose

Originally added as part of Building Microservices In Go: Containerization with Docker, docker compose has evolved and with it the way to run everything locally. Make sure you are running a recent version of Docker Compose. The configuration in this repository and the instructions below are known to work for at least the following versions:

  • Engine: 27.4.0, and
  • Compose: v2.31.0-desktop.2

This project takes advantage of Go's build constrains and Docker's arguments to build the ElasticSearch indexers and to run the rest-server using any of the following types of message broker:

  • Redis (default one)
  • RabbitMQ
  • Kafka

The docker compose instructions are executed in the form of:

docker compose -f compose.yml -f compose.<type>.yml <command>

Where:

  • <type>: Indicates what message broker to use, and effectively match the compose filename itself. The three supported values are:
    1. rabbitmq,
    2. kafka, and
    3. redis (default value when building the rest-server binary).
  • <command>: Indicates the docker compose command to use.

For example to build images using RabbitMQ as the message broker you execute:

docker compose -f compose.yml -f compose.rabbitmq.yml build

Then to start the containers you execute:

docker compose -f compose.yml -f compose.rabbitmq.yml up

Once all the containers are up you can access the Swagger UI at http://localhost:9234/static/swagger-ui/.

Documentation

Overview

Package todo provides primitives to interact with the openapi HTTP API.

Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.5.0 DO NOT EDIT.

Package todo represents the ToDo REST API client generated.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewCreateTaskRequest

func NewCreateTaskRequest(server string, body CreateTaskJSONRequestBody) (*http.Request, error)

NewCreateTaskRequest calls the generic CreateTask builder with application/json body

func NewCreateTaskRequestWithBody

func NewCreateTaskRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error)

NewCreateTaskRequestWithBody generates requests for CreateTask with any type of body

func NewDeleteTaskRequest

func NewDeleteTaskRequest(server string, id googleuuid.UUID) (*http.Request, error)

NewDeleteTaskRequest generates requests for DeleteTask

func NewReadTaskRequest

func NewReadTaskRequest(server string, id googleuuid.UUID) (*http.Request, error)

NewReadTaskRequest generates requests for ReadTask

func NewSearchTaskRequest

func NewSearchTaskRequest(server string, body SearchTaskJSONRequestBody) (*http.Request, error)

NewSearchTaskRequest calls the generic SearchTask builder with application/json body

func NewSearchTaskRequestWithBody

func NewSearchTaskRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error)

NewSearchTaskRequestWithBody generates requests for SearchTask with any type of body

func NewUpdateTaskRequest

func NewUpdateTaskRequest(server string, id googleuuid.UUID, body UpdateTaskJSONRequestBody) (*http.Request, error)

NewUpdateTaskRequest calls the generic UpdateTask builder with application/json body

func NewUpdateTaskRequestWithBody

func NewUpdateTaskRequestWithBody(server string, id googleuuid.UUID, contentType string, body io.Reader) (*http.Request, error)

NewUpdateTaskRequestWithBody generates requests for UpdateTask with any type of body

Types

type Client

type Client struct {
	// The endpoint of the server conforming to this interface, with scheme,
	// https://api.deepmap.com for example. This can contain a path relative
	// to the server, such as https://api.deepmap.com/dev-test, and all the
	// paths in the swagger spec will be appended to the server.
	Server string

	// Doer for performing requests, typically a *http.Client with any
	// customized settings, such as certificate chains.
	Client HttpRequestDoer

	// A list of callbacks for modifying requests which are generated before sending over
	// the network.
	RequestEditors []RequestEditorFn
}

Client which conforms to the OpenAPI3 specification for this service.

func NewClient

func NewClient(server string, opts ...ClientOption) (*Client, error)

Creates a new Client, with reasonable defaults

func (*Client) CreateTask

func (c *Client) CreateTask(ctx context.Context, body CreateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) CreateTaskWithBody

func (c *Client) CreateTaskWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) DeleteTask

func (c *Client) DeleteTask(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) ReadTask

func (c *Client) ReadTask(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) SearchTask

func (c *Client) SearchTask(ctx context.Context, body SearchTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) SearchTaskWithBody

func (c *Client) SearchTaskWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) UpdateTask

func (c *Client) UpdateTask(ctx context.Context, id googleuuid.UUID, body UpdateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)

func (*Client) UpdateTaskWithBody

func (c *Client) UpdateTaskWithBody(ctx context.Context, id googleuuid.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)

type ClientInterface

type ClientInterface interface {
	// CreateTaskWithBody request with any body
	CreateTaskWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)

	CreateTask(ctx context.Context, body CreateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)

	// SearchTaskWithBody request with any body
	SearchTaskWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)

	SearchTask(ctx context.Context, body SearchTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)

	// DeleteTask request
	DeleteTask(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*http.Response, error)

	// ReadTask request
	ReadTask(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*http.Response, error)

	// UpdateTaskWithBody request with any body
	UpdateTaskWithBody(ctx context.Context, id googleuuid.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)

	UpdateTask(ctx context.Context, id googleuuid.UUID, body UpdateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
}

The interface specification for the client above.

type ClientOption

type ClientOption func(*Client) error

ClientOption allows setting custom parameters during construction

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL overrides the baseURL.

func WithHTTPClient

func WithHTTPClient(doer HttpRequestDoer) ClientOption

WithHTTPClient allows overriding the default Doer, which is automatically created using http.Client. This is useful for tests.

func WithRequestEditorFn

func WithRequestEditorFn(fn RequestEditorFn) ClientOption

WithRequestEditorFn allows setting up a callback function, which will be called right before sending the request. This can be used to mutate the request.

type ClientWithResponses

type ClientWithResponses struct {
	ClientInterface
}

ClientWithResponses builds on ClientInterface to offer response payloads

func NewClientWithResponses

func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error)

NewClientWithResponses creates a new ClientWithResponses, which wraps Client with return type handling

func (*ClientWithResponses) CreateTaskWithBodyWithResponse

func (c *ClientWithResponses) CreateTaskWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateTaskResponse, error)

CreateTaskWithBodyWithResponse request with arbitrary body returning *CreateTaskResponse

func (*ClientWithResponses) CreateTaskWithResponse

func (c *ClientWithResponses) CreateTaskWithResponse(ctx context.Context, body CreateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateTaskResponse, error)

func (*ClientWithResponses) DeleteTaskWithResponse

func (c *ClientWithResponses) DeleteTaskWithResponse(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*DeleteTaskResponse, error)

DeleteTaskWithResponse request returning *DeleteTaskResponse

func (*ClientWithResponses) ReadTaskWithResponse

func (c *ClientWithResponses) ReadTaskWithResponse(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*ReadTaskResponse, error)

ReadTaskWithResponse request returning *ReadTaskResponse

func (*ClientWithResponses) SearchTaskWithBodyWithResponse

func (c *ClientWithResponses) SearchTaskWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SearchTaskResponse, error)

SearchTaskWithBodyWithResponse request with arbitrary body returning *SearchTaskResponse

func (*ClientWithResponses) SearchTaskWithResponse

func (c *ClientWithResponses) SearchTaskWithResponse(ctx context.Context, body SearchTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*SearchTaskResponse, error)

func (*ClientWithResponses) UpdateTaskWithBodyWithResponse

func (c *ClientWithResponses) UpdateTaskWithBodyWithResponse(ctx context.Context, id googleuuid.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateTaskResponse, error)

UpdateTaskWithBodyWithResponse request with arbitrary body returning *UpdateTaskResponse

func (*ClientWithResponses) UpdateTaskWithResponse

func (c *ClientWithResponses) UpdateTaskWithResponse(ctx context.Context, id googleuuid.UUID, body UpdateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateTaskResponse, error)

type ClientWithResponsesInterface

type ClientWithResponsesInterface interface {
	// CreateTaskWithBodyWithResponse request with any body
	CreateTaskWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateTaskResponse, error)

	CreateTaskWithResponse(ctx context.Context, body CreateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateTaskResponse, error)

	// SearchTaskWithBodyWithResponse request with any body
	SearchTaskWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SearchTaskResponse, error)

	SearchTaskWithResponse(ctx context.Context, body SearchTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*SearchTaskResponse, error)

	// DeleteTaskWithResponse request
	DeleteTaskWithResponse(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*DeleteTaskResponse, error)

	// ReadTaskWithResponse request
	ReadTaskWithResponse(ctx context.Context, id googleuuid.UUID, reqEditors ...RequestEditorFn) (*ReadTaskResponse, error)

	// UpdateTaskWithBodyWithResponse request with any body
	UpdateTaskWithBodyWithResponse(ctx context.Context, id googleuuid.UUID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateTaskResponse, error)

	UpdateTaskWithResponse(ctx context.Context, id googleuuid.UUID, body UpdateTaskJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateTaskResponse, error)
}

ClientWithResponsesInterface is the interface specification for the client with responses above.

type CreateTaskJSONBody

type CreateTaskJSONBody struct {
	Dates       *Dates    `json:"dates,omitempty"`
	Description string    `json:"description"`
	Priority    *Priority `json:"priority,omitempty"`
}

CreateTaskJSONBody defines parameters for CreateTask.

type CreateTaskJSONRequestBody

type CreateTaskJSONRequestBody CreateTaskJSONBody

CreateTaskJSONRequestBody defines body for CreateTask for application/json ContentType.

type CreateTaskResponse

type CreateTaskResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON201      *CreateTasksResponse
	JSON400      *ErrorResponse
	JSON500      *ErrorResponse
}

func ParseCreateTaskResponse

func ParseCreateTaskResponse(rsp *http.Response) (*CreateTaskResponse, error)

ParseCreateTaskResponse parses an HTTP response from a CreateTaskWithResponse call

func (CreateTaskResponse) Status

func (r CreateTaskResponse) Status() string

Status returns HTTPResponse.Status

func (CreateTaskResponse) StatusCode

func (r CreateTaskResponse) StatusCode() int

StatusCode returns HTTPResponse.StatusCode

type CreateTasksRequest

type CreateTasksRequest struct {
	Dates       *Dates    `json:"dates,omitempty"`
	Description string    `json:"description"`
	Priority    *Priority `json:"priority,omitempty"`
}

CreateTasksRequest defines model for CreateTasksRequest.

type CreateTasksResponse

type CreateTasksResponse struct {
	Task Task `json:"task"`
}

CreateTasksResponse defines model for CreateTasksResponse.

type Dates

type Dates struct {
	// Due When the task is expected to be due, seconds are dropped.
	Due *time.Time `json:"due"`

	// Start When the task is expected to begin, seconds are dropped.
	Start *time.Time `json:"start"`
}

Dates defines model for Dates.

type DeleteTaskResponse

type DeleteTaskResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON500      *ErrorResponse
}

func ParseDeleteTaskResponse

func ParseDeleteTaskResponse(rsp *http.Response) (*DeleteTaskResponse, error)

ParseDeleteTaskResponse parses an HTTP response from a DeleteTaskWithResponse call

func (DeleteTaskResponse) Status

func (r DeleteTaskResponse) Status() string

Status returns HTTPResponse.Status

func (DeleteTaskResponse) StatusCode

func (r DeleteTaskResponse) StatusCode() int

StatusCode returns HTTPResponse.StatusCode

type ErrorResponse

type ErrorResponse struct {
	Error string `json:"error"`
}

ErrorResponse defines model for ErrorResponse.

type HttpRequestDoer

type HttpRequestDoer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer performs HTTP requests.

The standard http.Client implements this interface.

type Priority

type Priority string

Priority defines model for Priority.

const (
	PriorityHigh   Priority = "high"
	PriorityLow    Priority = "low"
	PriorityMedium Priority = "medium"
	PriorityNone   Priority = "none"
)

Defines values for Priority.

type ReadTaskResponse

type ReadTaskResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON200      *ReadTasksResponse
	JSON500      *ErrorResponse
}

func ParseReadTaskResponse

func ParseReadTaskResponse(rsp *http.Response) (*ReadTaskResponse, error)

ParseReadTaskResponse parses an HTTP response from a ReadTaskWithResponse call

func (ReadTaskResponse) Status

func (r ReadTaskResponse) Status() string

Status returns HTTPResponse.Status

func (ReadTaskResponse) StatusCode

func (r ReadTaskResponse) StatusCode() int

StatusCode returns HTTPResponse.StatusCode

type ReadTasksResponse

type ReadTasksResponse struct {
	Task *Task `json:"task,omitempty"`
}

ReadTasksResponse defines model for ReadTasksResponse.

type RequestEditorFn

type RequestEditorFn func(ctx context.Context, req *http.Request) error

RequestEditorFn is the function signature for the RequestEditor callback function

type SearchTaskJSONBody

type SearchTaskJSONBody struct {
	Description *string   `json:"description"`
	From        int64     `json:"from"`
	IsDone      *bool     `json:"isDone"`
	Priority    *Priority `json:"priority,omitempty"`
	Size        int64     `json:"size"`
}

SearchTaskJSONBody defines parameters for SearchTask.

type SearchTaskJSONRequestBody

type SearchTaskJSONRequestBody SearchTaskJSONBody

SearchTaskJSONRequestBody defines body for SearchTask for application/json ContentType.

type SearchTaskResponse

type SearchTaskResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON200      *SearchTasksResponse
	JSON400      *ErrorResponse
	JSON500      *ErrorResponse
}

func ParseSearchTaskResponse

func ParseSearchTaskResponse(rsp *http.Response) (*SearchTaskResponse, error)

ParseSearchTaskResponse parses an HTTP response from a SearchTaskWithResponse call

func (SearchTaskResponse) Status

func (r SearchTaskResponse) Status() string

Status returns HTTPResponse.Status

func (SearchTaskResponse) StatusCode

func (r SearchTaskResponse) StatusCode() int

StatusCode returns HTTPResponse.StatusCode

type SearchTasksRequest

type SearchTasksRequest struct {
	Description *string   `json:"description"`
	From        int64     `json:"from"`
	IsDone      *bool     `json:"isDone"`
	Priority    *Priority `json:"priority,omitempty"`
	Size        int64     `json:"size"`
}

SearchTasksRequest defines model for SearchTasksRequest.

type SearchTasksResponse

type SearchTasksResponse struct {
	Tasks *[]Task `json:"tasks,omitempty"`
	Total *int64  `json:"total,omitempty"`
}

SearchTasksResponse defines model for SearchTasksResponse.

type Task

type Task struct {
	Dates       *Dates          `json:"dates,omitempty"`
	Description string          `json:"description"`
	ID          googleuuid.UUID `json:"id"`
	IsDone      *bool           `json:"isDone,omitempty"`
	Priority    *Priority       `json:"priority,omitempty"`
}

Task defines model for Task.

type UpdateTaskJSONBody

type UpdateTaskJSONBody struct {
	Dates       *Dates    `json:"dates,omitempty"`
	Description *string   `json:"description,omitempty"`
	IsDone      *bool     `json:"isDone,omitempty"`
	Priority    *Priority `json:"priority,omitempty"`
}

UpdateTaskJSONBody defines parameters for UpdateTask.

type UpdateTaskJSONRequestBody

type UpdateTaskJSONRequestBody UpdateTaskJSONBody

UpdateTaskJSONRequestBody defines body for UpdateTask for application/json ContentType.

type UpdateTaskResponse

type UpdateTaskResponse struct {
	Body         []byte
	HTTPResponse *http.Response
	JSON400      *ErrorResponse
	JSON500      *ErrorResponse
}

func ParseUpdateTaskResponse

func ParseUpdateTaskResponse(rsp *http.Response) (*UpdateTaskResponse, error)

ParseUpdateTaskResponse parses an HTTP response from a UpdateTaskWithResponse call

func (UpdateTaskResponse) Status

func (r UpdateTaskResponse) Status() string

Status returns HTTPResponse.Status

func (UpdateTaskResponse) StatusCode

func (r UpdateTaskResponse) StatusCode() int

StatusCode returns HTTPResponse.StatusCode

type UpdateTasksRequest

type UpdateTasksRequest struct {
	Dates       *Dates    `json:"dates,omitempty"`
	Description *string   `json:"description,omitempty"`
	IsDone      *bool     `json:"isDone,omitempty"`
	Priority    *Priority `json:"priority,omitempty"`
}

UpdateTasksRequest defines model for UpdateTasksRequest.

Directories

Path Synopsis
cmd
rest-server command
Package internal defines the types used to create Tasks and their corresponding attributes.
Package internal defines the types used to create Tasks and their corresponding attributes.
elasticsearch
Package elasticsearch implements the Elasticsearch repository.
Package elasticsearch implements the Elasticsearch repository.
envvar/envvartesting
Code generated by counterfeiter.
Code generated by counterfeiter.
kafka
Package kafka implements the Kafka repository to publish events.
Package kafka implements the Kafka repository to publish events.
memcached
Package memcached implements the memcached repository to cache tasks.
Package memcached implements the memcached repository to cache tasks.
memcached/memcachedtesting
Code generated by counterfeiter.
Code generated by counterfeiter.
postgresql
Package postgresql implements the PostgreSQL repository for tasks.
Package postgresql implements the PostgreSQL repository for tasks.
rabbitmq
Package rabbitmq implements the RabbitMQ repository to publish events.
Package rabbitmq implements the RabbitMQ repository to publish events.
redis
Package redis implements the Redis repository to publish events.
Package redis implements the Redis repository to publish events.
rest
Package rest provides primitives to interact with the openapi HTTP API.
Package rest provides primitives to interact with the openapi HTTP API.
rest/resttesting
Code generated by counterfeiter.
Code generated by counterfeiter.
service/servicetesting
Code generated by counterfeiter.
Code generated by counterfeiter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL