Connect a Database

Idea

  • We’ve got a service type responsible for managing a customer database
  • In the example It resides in the same package and is only for encapsulating the database

Implementation

package customer

import (
    "net/http"

    "./pkg/httpx"
)

const (
    // Prefix for API calls.
    apiPrefix = "/api/v1"
    
    // Name of the customer resource.
    ressourceName = "customer"
)

type Handler struct {
    service *Service
}

// NewHandler returns the wrapped web handler for the customer handler.
func NewHandler(service *Service) http.Handler {
    return httpx.NewMethodHandler(&Handler{
        service: service,
    })
}

// ServeHTTPPost creates the customer.
func (h *Handler) ServeHTTPPost(w http.ResponseWriter, r *http.Request) {
    var c Customer
    err := httpx.ReadBody(r, &c)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    if !httpx.PathToResources(apiPrefix).IsPath(ressourceName) {
        http.Error(w, "missing or bad resource", http.StatusBadRequest)
        return
    }
    err = h.service.Create(c)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    http.Error(w, "", http.StatusCreated)
}

// ServeHTTPGet reads the customer.
func (h *Handler) ServeHTTPGet(w http.ResponseWriter, r *http.Request) {
    ress := httpx.PathToResources(r, apiPrefix)
    if !ress.IsPath(ressourceName) {
        http.Error(w, "missing or bad resource", http.StatusBadRequest)
        return
    }
    if ress[0].ID == "" {
        // Handling of queries is still missing in httpx. Needs a kind of
        // query parsing like
        //
        // args := httpx.QueryToArguments(r)
        // cs, err := h.service.Find(args)   
        http.Error(w, http.StatusText(http.StatusNotImplemented), http.StatusNotImplemented)
        return
    }
    c, err := h.service.Read(ress[0].ID)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    err = httpx.WriteBody(w, c)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
}

// ServeHTTPPut updates the customer.
func (h *Handler) ServeHTTPPut(w http.ResponseWriter, r *http.Request) {
    var c Customer
    err := httpx.ReadBody(r, &c)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    ress := httpx.PathToResources(r, apiPrefix)
    if !ress.IsPath(ressourceName) {
        http.Error(w, "missing or bad resource", http.StatusBadRequest)
        return
    }
    err = h.service.Update(ress.PathID(ressourceName), c)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    http.Error(w, "", http.StatusNoContent)
}

// ServeHTTPDelete deletes the customer.
func (h *Handler) ServeHTTPDelete(w http.ResponseWriter, r *http.Request) {
    ress := httpx.PathToResources(r, apiPrefix)
    if !ress.IsPath(ressourceName) {
        http.Error(w, "missing or bad resource", http.StatusBadRequest)
        return
    }
    err := h.service.Delete(ress.PathID(ressourceName))
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    http.Error(w, "", http.StatusNoContent)
}