To start our project we will use this github to save our steps during the project.
In this first step we will define a folder structure, domain and controllers with a simple crud (GET, POST, PUT and DELETE).
First of all, we will see how our folder structure will be, after a lot of time reading articles and posts, creating projects and improving my code i decide to use a structure folder like golang standard layout with some changes.
Our Structure
In this first step our structure will look like this:
📦hero-api-golang
┣ 📂cmd
┃ ┗ 📂http
┃ ┃ ┣ 📂handler
┃ ┃ ┃ ┣ 📜book.go
┃ ┃ ┃ ┗ 📜router.go
┃ ┃ ┗ 📜main.go // Our entrypoint project
┣ 📜.gitignore
┣ 📜go.mod
┣ 📜go.sum
┗ 📜README.md
In this post we will see all this files and improve this structure in the next post while we building our API.
Initializing the project
To initialize the golang project we need to start the goland dependency mananger, we will use the go mod.
go mod init github.com/maaarkin/hero-api-golang
change /maaarkin/hero-api-golang to /your-user/your-project-name
Every application need a entrypoint, in our case we will represent by cmd/http/main.go file.
To minify the post, we will share only the code necessary to explain what we need, the complete code you can check in the github
func main() {
//delegate to start our Http Server
handler.StartServer()
}
the StartServer() function manage everything that envolve http entrypoint like handler register, middleware register and error handler.
package handler
import (
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"log"
"net/http"
)
type handlers struct {
Book *BookHandler
}
func initHandlers() handlers {
return handlers{
Book: NewBookHandler(),
}
}
func StartServer() {
log.Println("Initializing the Http Server at localhost:8080")
handlers := initHandlers()
r := chi.NewRouter()
r.Use(middleware.RequestID)
r.Use(middleware.RealIP)
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Route("/v1", func(r chi.Router) {
r.Route("/books", handlers.Book.Route)
})
http.ListenAndServe(":8080", r)
}
To build our http server we will use chi, if you look the chi documentation you will see very similarities with our start code. The only difference here is that we separate the handler code to another file.
In this case you don't need the chi, the go provide a good http server but chi help us with a good idiomatic and composable router for building Go HTTP services, be free to choice anyone.
In initHandlers() we declare ours handlers, in other post i will tell you why we adopt this approach (IoC :D), but for now that function is responsible to group our API handlers.
And by now, check our BookHandler.
package handler
import (
"github.com/go-chi/chi"
"net/http"
)
type BookHandler struct{}
func NewBookHandler() *BookHandler {
return &BookHandler{}
}
func (b *BookHandler) Route(r chi.Router) {
r.Get("/hello", b.hello)
}
func (*BookHandler) hello(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello World"))
}
The Route(...) function that we use in the StartServer(...) provide an extension for /books. If we expose any endpoint to the client and this endpoint envolve book domain, we use this handler to expose the service.
To start the handler we will begin with a Hello World, just to check if the http server it's ok.
λ curl http://localhost:8080/v1/books/hello
Hello World
If you check the server log, you will see something like this
2020/07/01 18:56:36 [LAPTOP-JNKKGDL0/hg3pWpHa7y-000002] "GET http://localhost:8080/v1/books/hello HTTP/1.1" from [::1]:50046 - 200 11B in 0s
At this moment we have our http server started and we are ready to go to the next step, write our domain and service layer. But this content belongs to step-2.
Top comments (0)