DEV Community

Cover image for Getting a response!
Marcos Filho
Marcos Filho

Posted on

Getting a response!

In the last step, we show our service layer consuming the repository layer but we don't see the data.

In this post, we will keep covering the code to show you how we consume the service layer in the handler and mount the response.

Before demonstrating the handler code, we need to make some changes in the container/container.go. Now we need to instantiate the repository layer that we talk in the last step and pass this new repository into the service layer in the constructor

// ...
func Inject() Container {

    //stores - this is new
    bookStore := repository.NewBookStoreInMemory()

    //init services
    bs := service.NewBookService(bookStore)
// ...
}

Enter fullscreen mode Exit fullscreen mode

Now, as you can see, we instantiate the repository and delivery the implementation to the service layer, Now our Container with services will have a service that communicates with a persistence layer (in memory at the moment).

Looking to our handler/book.go you will see new methods and our constructor with a new required information, the service layer.

package handler

import (
    "encoding/json"
    "net/http"

    "github.com/go-chi/chi"
    "github.com/maaarkin/hero-api-golang/internal/service"
)

type BookHandler struct {
    bookService service.BookService
}

func NewBookHandler(bs service.BookService) *BookHandler {
    return &BookHandler{bs}
}

func (b *BookHandler) Route(r chi.Router) {
    r.Get("/hello", b.hello)
    r.Get("/", b.getAll)
}

func (*BookHandler) hello(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Hello World"))
}

func (h *BookHandler) getAll(w http.ResponseWriter, r *http.Request) {
    if results, err := h.bookService.FindAll(); err != nil {
        addDefaultHeaders(w)
        writeData(
            w,
            map[string]interface{}{
                "Status":      http.StatusInternalServerError,
                "Description": "Internal error, please report to admin",
            },
        )
    } else {
        if results != nil && len(*results) > 0 {
            addDefaultHeaders(w)
            w.WriteHeader(http.StatusOK)
            writeData(w, results)
        } else {
            addDefaultHeaders(w)
            w.WriteHeader(http.StatusNoContent)
        }
    }
}

func addDefaultHeaders(w http.ResponseWriter) {
    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
}

func writeData(w http.ResponseWriter, data interface{}) {
    if bytes, e := json.Marshal(data); e != nil {
        http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
    } else {
        if _, e := w.Write(bytes); e != nil {
            http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Now you will see three new method (getAll, addDefaultHeaders and writeData). The getAll is our new method to show all books that our service will provide to us. The addDefaultHeaders is just a helper function to group some headers necessary to our response being formated in json and the writeData is a helper function too that will helper us to write our data into the response.

The getAll is too simple, we call our service layer and provide a specific HTTP error code and a message error if our service returns an error. If our service does not throw any error we just validate if the result has some content and delivery a 200 Http Code (OK) with the content or delivery a 204 Http Code (No Content).

Now if you start the application and get the endpoint /v1/books, you will receive a json with two objects.

λ curl http://localhost:8080/v1/books
[{"Id":1,"Title":"Title 1","Author":"MarkMark","NumberPages":101},{"Id":2,"Title":"Title 2","Author":"MarkMark 2","NumberPages":203}]
Enter fullscreen mode Exit fullscreen mode

But... I think our handler is too verbose at the moment.. in the next step we will refactor the code to be more readable.

See ya!

Discussion (0)