Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/zett-8/go-clean-echo
Go Echo Simple API with Clean architecture
https://github.com/zett-8/go-clean-echo
auth0 auth0-jwt clean-architecture docker echo go golang jwt jwt-authentication postgres sql-migrate swagger testing
Last synced: 24 days ago
JSON representation
Go Echo Simple API with Clean architecture
- Host: GitHub
- URL: https://github.com/zett-8/go-clean-echo
- Owner: zett-8
- Created: 2022-07-27T12:44:23.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2023-03-10T19:22:31.000Z (over 1 year ago)
- Last Synced: 2024-10-02T06:41:24.203Z (about 1 month ago)
- Topics: auth0, auth0-jwt, clean-architecture, docker, echo, go, golang, jwt, jwt-authentication, postgres, sql-migrate, swagger, testing
- Language: Go
- Homepage:
- Size: 216 KB
- Stars: 63
- Watchers: 1
- Forks: 13
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Go Echo Simple API with Clean Architecture
[![Build & Unit Test](https://github.com/zett-8/go-clean-echo/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/zett-8/go-clean-echo/actions/workflows/test.yml)
## 🤓 About this repo
This is a sample of Web API built by Go (Echo) according to *Clean architecture*.
But I have to say that I'm not a backend specialist nor of Go, so Clean architecture here could be wrong or missing essential concepts. (I'm sorry in that case)This sample consists of 4 layers, **"Models"**, **"Stores"**, **"Services(Logic)"** and **"Handlers(Framework)"**, although naming might differ in other samples.
Each layer only concerns/handles its inside layer, not the other way around.
This makes it super easy to replace each layer. (also good for testing)![clean architecture](./utils/img.png)
#### What you might find helpful in this repo.
- [x] [echo](https://github.com/labstack/echo)(Framework) for handling requests
- [x] Clean architecture
- [x] zap([uber-go/zap](https://github.com/uber-go/zap)) for logging
- [x] swagger([swaggo/echo-swagger](https://github.com/swaggo/echo-swagger)) for documentation
- [x] sql-migrate([rubenv/sql-migrate](https://github.com/rubenv/sql-migrate)) for migration
- [x] Database transaction in service layer
- [x] sqlmock ([DATA-DOG/go-sqlmock](https://github.com/DATA-DOG/go-sqlmock)) for testing
- [x] Multi-stage build for optimized docker image
- [x] Hot reload([cosmtrek/air](https://github.com/cosmtrek/air)) for efficient development
- [x] JWT authentication([auth0/go-jwt-middleware](https://github.com/auth0/go-jwt-middleware/)) with [Auth0](https://auth0.com/) for security
- [x] Automated testing on GitHub actions
## 👟 How to run
Install.
```shell
git clone [email protected]:zett-8/go-clean-echo.gitcd go-clean-echo
```Download dependencies.
```shell
go mod download
```Fill out auth0 config to run with JWT authentication. Or simply disable JWT middleware
```go
// configs/auth0.go
var Auth0Config = Auth0ConfigType{
Domain: "****",
ClientID: "****",
Audience: []string{"****"},
Issuer: "****",
SignatureAlgorithm: validator.RS256,
CacheDuration: 15 * time.Minute,
}// or
// handlers/handlers.go
func SetApi(e *echo.Echo, h *Handlers, m echo.MiddlewareFunc) {
g := e.Group("/api/v1")
g.Use(m) // <- Comment out this line
}
```Run docker.
```shell
docker-compose up
```
## 🌱 Tips
### Use multi-stage build
Using multistage build reduces the size of the docker image.```dockerfile
ARG PORT=8888# Base image for local development. Use 'air' for hot reload.
FROM golang:1.18-alpine as baseARG PORT
ENV PORT=$PORT
ENV GO_ENV=developmentWORKDIR /go/app/base
COPY go.mod .
COPY go.sum .RUN apk add build-base
RUN go mod download
RUN go install github.com/cosmtrek/air@latestCOPY . .
# The image for build. Set CGO_ENABLE=0 not to build unnecessary binary.
FROM golang:1.18-alpine as builderARG PORT
ENV PORT=$PORTWORKDIR /go/app/builder
COPY --from=base /go/app/base /go/app/builder
RUN CGO_ENABLED=0 go build -o main -ldflags "-s -w"
# The final image to run
FROM gcr.io/distroless/static-debian11 as productionARG PORT
ENV PORT=$PORTWORKDIR /go/app/src
COPY --from=builder /go/app/builder/main /go/app/src/main
EXPOSE $PORT
CMD ["/go/app/src/main"]
```### Use "Air" for hot reload
We used to have other reloaders such as [realize](https://github.com/oxequa/realize).
But it seems no longer be developed or maintained, so I recommend to use "air"> [cosmtrek/air](https://github.com/cosmtrek/air).
### Mock a unit for testing
Here is one example to mock "service" for "handler" test.Let's say this is the service to mock.
```go
// services/services.go
type Services struct {
AuthorService
BookService
}func New(s *stores.Stores) *Services {
return &Services{
AuthorService: &authorService{s.AuthorStore},
BookService: &bookService{s.BookStore},
}
}// services/author.go
type (
AuthorService interface {
GetAuthors() ([]models.Author, error)
DeleteAuthor(id int) error
}authorService struct {
store stores.AuthorStore
}
)func (s *AuthorServiceContext) GetAuthors() ([]models.Author, error) {
r, err := s.store.Get()
return r, err
}func (s *AuthorServiceContext) DeleteAuthor(id int) error {
err := s.store.DeleteById(id)
return err
}
```And in /handlers/author_test.go. Declare Mock struct.
```go
// handlers/author_test.go
type MockAuthorService struct {
services.AuthorService
MockGetAuthors func() ([]models.Author, error)
MockDeleteAuthorById func(id int) error
}func (m *MockAuthorService) GetAuthors() ([]models.Author, error) {
return m.MockGetAuthors()
}func (m *MockAuthorService) DeleteAuthor(id int) error {
return m.MockDeleteAuthorById(id)
}
```Then use it as mockService.
```go
// handlers/author_test.go
func TestGetAuthorsSuccessCase(t *testing.T) {
s := &MockAuthorService{
MockGetAuthors: func () ([]models.Author, error) {
var r []models.Author
return r, nil
},
}
mockService := &services.Services{AuthorService: s}
e := Echo()
h := New(mockService)
}
```
## 📃 API Document (Swagger)
```text
http://localhost:8888/swagger/index.html
```
## ✅ Testing
```shell
make test
```
## 💜 References
[bxcodec/go-clean-arch](https://github.com/bxcodec/go-clean-arch)
[onakrainikoff/echo-rest-api](https://github.com/onakrainikoff/echo-rest-api)
[satishbabariya/go-echo-auth0-middleware](https://github.com/satishbabariya/go-echo-auth0-middleware)
[xesina/golang-echo-realworld-example-app](https://github.com/xesina/golang-echo-realworld-example-app)