Files
LK_API_Temp/cmd/api/posts.go
T

198 lines
4.5 KiB
Go

package main
import (
"errors"
"net/http"
"strconv"
"github.com/FernandoVideira/LK_API_Temp/internal/store"
"github.com/go-chi/chi/v5"
)
type postKey string
const postCtx postKey = "post"
type CreatePostPayload struct {
Title string `json:"title" validate:"required,max=100"`
Content string `json:"content" validate:"required,max=1000"`
Tags []string `json:"tags"`
}
// CreatePost godoc
//
// @Summary Creates a new Post
// @Description Creates a new Post
// @Tags posts
// @Accept json
// @Produce json
// @Param in body CreatePostPayload true "Post Payload"
// @Success 200 {object} store.Post
// @Failure 400 {object} error
// @Failure 404 {object} error
// @Failure 500 {object} error
// @Security ApiKeyAuth
// @Router /posts [post]
func (api *api) createPostHandler(w http.ResponseWriter, r *http.Request) {
var payload CreatePostPayload
if err := readJSON(w, r, &payload); err != nil {
api.badRequestError(w, r, err)
return
}
if err := Validate.Struct(payload); err != nil {
api.badRequestError(w, r, err)
return
}
user := getUserFromContext(r)
post := &store.Post{
UserID: user.ID,
Title: payload.Title,
Content: payload.Content,
Tags: payload.Tags,
}
ctx := r.Context()
if err := api.store.Posts.Create(ctx, post); err != nil {
api.internalServerError(w, r, err)
return
}
if err := api.jsonResponse(w, http.StatusCreated, post); err != nil {
api.internalServerError(w, r, err)
return
}
}
// GetPost godoc
//
// @Summary Fetches a Post
// @Description Fetches a Post by ID
// @Tags posts
// @Accept json
// @Produce json
// @Param id path int true "Post ID"
// @Success 200 {object} store.Post
// @Failure 400 {object} error
// @Failure 404 {object} error
// @Failure 500 {object} error
// @Security ApiKeyAuth
// @Router /posts/{id} [get]
func (api *api) getPostHandler(w http.ResponseWriter, r *http.Request) {
post := getPostFromContext(r)
comments, err := api.store.Comments.GetByPostID(r.Context(), post.ID)
if err != nil {
api.internalServerError(w, r, err)
return
}
post.Comments = comments
if err := api.jsonResponse(w, http.StatusOK, post); err != nil {
api.internalServerError(w, r, err)
return
}
}
type UpdatePostPayload struct {
Title *string `json:"title" validate:"omitempty,max=100"`
Content *string `json:"content" validate:"omitempty,max=1000"`
}
// UpdatePost godoc
//
// @Summary Update a Post
// @Description Update a Post by ID
// @Tags posts
// @Accept json
// @Produce json
// @Param id path int true "Post ID"
// @Param in body UpdatePostPayload true "Post Payload"
// @Success 200 {object} store.Post
// @Failure 400 {object} error
// @Failure 404 {object} error
// @Failure 500 {object} error
// @Security ApiKeyAuth
// @Router /posts/{id} [patch]
func (api *api) updatePostHandler(w http.ResponseWriter, r *http.Request) {
post := getPostFromContext(r)
var payload UpdatePostPayload
if err := readJSON(w, r, &payload); err != nil {
api.badRequestError(w, r, err)
return
}
if err := Validate.Struct(payload); err != nil {
api.badRequestError(w, r, err)
return
}
if payload.Content != nil {
post.Content = *payload.Content
}
if payload.Title != nil {
post.Title = *payload.Title
}
if err := api.store.Posts.Update(r.Context(), post); err != nil {
switch {
case errors.Is(err, store.ErrNotFound):
api.conflictError(w, r, err)
default:
api.internalServerError(w, r, err)
}
return
}
if err := api.jsonResponse(w, http.StatusOK, post); err != nil {
api.internalServerError(w, r, err)
return
}
}
// DeletePost godoc
//
// @Summary Deletes a Post
// @Description Deletse a Post by ID
// @Tags posts
// @Accept json
// @Produce json
// @Param id path int true "Post ID"
// @Success 204 {object} string
// @Failure 404 {object} error
// @Failure 500 {object} error
// @Security ApiKeyAuth
// @Router /posts/{id} [delete]
func (api *api) deletePostHandler(w http.ResponseWriter, r *http.Request) {
idParam := chi.URLParam(r, "id")
id, err := strconv.ParseInt(idParam, 10, 64)
if err != nil {
api.badRequestError(w, r, err)
return
}
ctx := r.Context()
if err := api.store.Posts.Delete(ctx, id); err != nil {
switch {
case errors.Is(err, store.ErrNotFound):
api.notFoundError(w, r, err)
default:
api.internalServerError(w, r, err)
}
return
}
w.WriteHeader(http.StatusNoContent)
}
func getPostFromContext(r *http.Request) *store.Post {
post, _ := r.Context().Value(postCtx).(*store.Post)
return post
}