DEV Community

Cover image for Getting a response!
Marcos Filho
Marcos Filho

Posted on

1 1

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!

API Trace View

How I Cut 22.3 Seconds Off an API Call with Sentry πŸ•’

Struggling with slow API calls? Dan Mindru walks through how he used Sentry's new Trace View feature to shave off 22.3 seconds from an API call.

Get a practical walkthrough of how to identify bottlenecks, split tasks into multiple parallel tasks, identify slow AI model calls, and more.

Read more β†’

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free β†’

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay