Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/components/parameters/ID.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ required: true
schema:
type: integer
format: int64

minimum: 1
Original file line number Diff line number Diff line change
@@ -1,43 +1,29 @@
package httpadapter

import "net/http"
import "context"

func (s *Server) GetProductByID(w http.ResponseWriter, r *http.Request, id int64) {
if id <= 0 {
writeError(w, http.StatusBadRequest, "INVALID_ID", "id must be a positive integer")
return
}
p, err := s.products.FetchByID(r.Context(), id)
func (s *Server) GetProductByID(ctx context.Context, request GetProductByIDRequestObject) (GetProductByIDResponseObject, error) {
product, err := s.products.FetchByID(ctx, request.Id)
if err != nil {
writeDomainError(w, err)
return
if resp, handled := getProductError(err); handled {
return resp, nil
}
return nil, err
}
writeJSON(w, http.StatusOK, presentProduct(p))

return okGetProduct(product), nil
}

func (s *Server) SearchProducts(w http.ResponseWriter, r *http.Request, params SearchProductsParams) {
q := ""
if params.Q != nil {
q = *params.Q
}
// Enforce OpenAPI minLength:3 for q when provided
if q != "" && len(q) < 3 {
writeError(w, http.StatusBadRequest, "INVALID_QUERY", "q must be at least 3 characters if provided")
return
}
page := 1
if params.Page != nil {
page = *params.Page
}
pageSize := 20
if params.PageSize != nil {
pageSize = *params.PageSize
}
items, total, err := s.products.Search(r.Context(), q, page, pageSize)
func (s *Server) SearchProducts(ctx context.Context, request SearchProductsRequestObject) (SearchProductsResponseObject, error) {
filters := newSearchFilters(request.Params)

items, total, err := s.products.Search(ctx, filters.query, filters.page, filters.pageSize)
if err != nil {
writeDomainError(w, err)
return
if resp, handled := searchProductsError(err); handled {
return resp, nil
}
return nil, err
}
resp := ProductList{Items: presentProducts(items), Page: page, PageSize: pageSize, Total: total}
writeJSON(w, http.StatusOK, resp)

return okSearchProducts(items, filters.page, filters.pageSize, total), nil
}
Original file line number Diff line number Diff line change
@@ -1,70 +1,56 @@
package httpadapter

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

"github.com/fightingBald/GoTuto/apps/product-query-svc/domain"
)

// DeleteProductByID implements OpenAPI operation: DELETE /products/{id}
func (s *Server) DeleteProductByID(w http.ResponseWriter, r *http.Request, id int64) {
if id <= 0 {
writeError(w, http.StatusBadRequest, "INVALID_ID", "id must be a positive integer")
return
func (s *Server) CreateProduct(ctx context.Context, request CreateProductRequestObject) (CreateProductResponseObject, error) {
product, err := newProductFromCreateBody(request.Body)
if err != nil {
if resp, handled := createProductError(err); handled {
return resp, nil
}
return nil, err
}
if err := s.products.Remove(r.Context(), id); err != nil {
writeDomainError(w, err)
return

id, err := s.products.Create(ctx, product)
if err != nil {
if resp, handled := createProductError(err); handled {
return resp, nil
}
return nil, err
}
w.WriteHeader(http.StatusNoContent)

product.ID = id

return okCreateProduct(product), nil
}

// CreateProduct implements POST /products
func (s *Server) CreateProduct(w http.ResponseWriter, r *http.Request) {
var in CreateProductJSONBody
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
writeError(w, http.StatusBadRequest, "INVALID_JSON", "invalid request body")
return
}
cents := amountToCents(in.Price)
p, err := domain.NewProduct(in.Name, cents, nil)
func (s *Server) UpdateProduct(ctx context.Context, request UpdateProductRequestObject) (UpdateProductResponseObject, error) {
product, err := newProductFromUpdateBody(request.Id, request.Body)
if err != nil {
writeDomainError(w, err)
return
if resp, handled := updateProductError(err); handled {
return resp, nil
}
return nil, err
}
id, err := s.products.Create(r.Context(), p)

updated, err := s.products.Update(ctx, product)
if err != nil {
writeDomainError(w, err)
return
if resp, handled := updateProductError(err); handled {
return resp, nil
}
return nil, err
}
created := *p
created.ID = id
writeJSON(w, http.StatusCreated, presentProduct(&created))

return okUpdateProduct(updated), nil
}

// UpdateProduct implements OpenAPI operation: PUT /products/{id}
func (s *Server) UpdateProduct(w http.ResponseWriter, r *http.Request, id int64) {
if id <= 0 {
writeError(w, http.StatusBadRequest, "INVALID_ID", "id must be a positive integer")
return
}
var in UpdateProductJSONBody
if err := json.NewDecoder(r.Body).Decode(&in); err != nil {
writeError(w, http.StatusBadRequest, "INVALID_JSON", "invalid request body")
return
}
cents := amountToCents(in.Price)
p, err := domain.NewProduct(in.Name, cents, nil)
if err != nil {
writeDomainError(w, err)
return
func (s *Server) DeleteProductByID(ctx context.Context, request DeleteProductByIDRequestObject) (DeleteProductByIDResponseObject, error) {
if err := s.products.Remove(ctx, request.Id); err != nil {
if resp, handled := deleteProductError(err); handled {
return resp, nil
}
return nil, err
}
p.ID = id
updated, err := s.products.Update(r.Context(), p)
if err != nil {
writeDomainError(w, err)
return
}
writeJSON(w, http.StatusOK, presentProduct(updated))

return okDeleteProduct(), nil
}
19 changes: 9 additions & 10 deletions apps/product-query-svc/adapters/inbound/http/handler_user_read.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package httpadapter

import "net/http"
import "context"

func (s *Server) GetUserByID(w http.ResponseWriter, r *http.Request, id int64) {
if id <= 0 {
writeError(w, http.StatusBadRequest, "INVALID_ID", "id must be a positive integer")
return
}
u, err := s.users.FetchByID(r.Context(), id)
func (s *Server) GetUserByID(ctx context.Context, request GetUserByIDRequestObject) (GetUserByIDResponseObject, error) {
user, err := s.users.FetchByID(ctx, request.Id)
if err != nil {
writeDomainError(w, err)
return
if resp, handled := getUserError(err); handled {
return resp, nil
}
return nil, err
}
writeJSON(w, http.StatusOK, presentUser(u))

return okGetUser(user), nil
}
34 changes: 17 additions & 17 deletions apps/product-query-svc/adapters/inbound/http/marketplaceapi.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions apps/product-query-svc/adapters/inbound/http/request_mappers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package httpadapter

import "github.com/fightingBald/GoTuto/apps/product-query-svc/domain"

const (
defaultPage = 1
defaultPageSize = 20
)

type searchFilters struct {
query string
page int
pageSize int
}

func newSearchFilters(params SearchProductsParams) searchFilters {
filters := searchFilters{
page: defaultPage,
pageSize: defaultPageSize,
}

if params.Q != nil {
filters.query = *params.Q
}
if params.Page != nil {
filters.page = *params.Page
}
if params.PageSize != nil {
filters.pageSize = *params.PageSize
}

return filters
}

func newProductFromCreateBody(body *CreateProductJSONRequestBody) (*domain.Product, error) {
if body == nil {
return nil, domain.ValidationError("invalid request body")
}
return domain.NewProduct(body.Name, amountToCents(body.Price), nil)
}

func newProductFromUpdateBody(id int64, body *UpdateProductJSONRequestBody) (*domain.Product, error) {
if body == nil {
return nil, domain.ValidationError("invalid request body")
}
product, err := domain.NewProduct(body.Name, amountToCents(body.Price), nil)
if err != nil {
return nil, err
}
product.ID = id
return product, nil
}
Loading