emdb/app/movie.go

125 lines
2.9 KiB
Go
Raw Normal View History

2023-12-16 14:45:38 +01:00
package app
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"net/http"
"github.com/google/uuid"
)
type Movie struct {
ID string `json:"id"`
Title string `json:"title"`
Year int `json:"year"`
IMDBID string `json:"imdb_id"`
WatchedOn string `json:"watched_on"`
Rating int `json:"rating"`
Comment string `json:"comment"`
}
type MovieAPI struct {
repo *SQLite
logger *slog.Logger
}
func NewMovieAPI(repo *SQLite, logger *slog.Logger) *MovieAPI {
return &MovieAPI{
repo: repo,
logger: logger.With("api", "movie"),
}
}
func (api *MovieAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger := api.logger.With("method", "serveHTTP")
movieID, _ := ShiftPath(r.URL.Path)
switch {
case r.Method == http.MethodGet && movieID != "":
api.Read(w, r, movieID)
case r.Method == http.MethodGet && movieID == "":
api.List(w, r)
case r.Method == http.MethodPost:
api.Create(w, r)
default:
Error(w, http.StatusNotFound, "unregistered path", fmt.Errorf("method %q with subpath %q was not registered in /movie", r.Method, movieID), logger)
}
}
func (api *MovieAPI) Read(w http.ResponseWriter, r *http.Request, movieID string) {
logger := api.logger.With("method", "read")
movie, err := api.repo.FindOne(movieID)
switch {
case errors.Is(err, sql.ErrNoRows):
w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w, `{"message":"not found"}`)
return
case err != nil:
Error(w, http.StatusInternalServerError, "could not get movie", err, logger)
return
}
resJson, err := json.Marshal(movie)
if err != nil {
Error(w, http.StatusInternalServerError, "could not marshal response", err, logger)
return
}
fmt.Fprint(w, string(resJson))
}
func (api *MovieAPI) Create(w http.ResponseWriter, r *http.Request) {
logger := api.logger.With("method", "create")
body, err := io.ReadAll(r.Body)
if err != nil {
Error(w, http.StatusBadRequest, "could not read body", err, logger)
return
}
defer r.Body.Close()
var movie *Movie
if err := json.Unmarshal(body, &movie); err != nil {
Error(w, http.StatusBadRequest, "could not unmarshal request body", err, logger)
return
}
movie.ID = uuid.New().String()
if err := api.repo.StoreMovie(movie); err != nil {
Error(w, http.StatusInternalServerError, "could not store movie", err, logger)
return
}
resBody, err := json.Marshal(movie)
if err != nil {
Error(w, http.StatusInternalServerError, "could not marshal movie", err, logger)
return
}
fmt.Fprint(w, string(resBody))
}
func (api *MovieAPI) List(w http.ResponseWriter, r *http.Request) {
logger := api.logger.With("method", "list")
movies, err := api.repo.FindAll()
if err != nil {
Error(w, http.StatusInternalServerError, "could not get movies", err, logger)
return
}
resBody, err := json.Marshal(movies)
if err != nil {
Error(w, http.StatusInternalServerError, "could not marshal movies", err, logger)
return
}
fmt.Fprint(w, string(resBody))
}