Skip to content

Commit

Permalink
feat: add pets APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
litsynp committed Aug 8, 2023
1 parent 27a8de6 commit c5b0024
Show file tree
Hide file tree
Showing 23 changed files with 1,398 additions and 293 deletions.
7 changes: 6 additions & 1 deletion api/views/common.go → api/commonviews/common.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package views
package commonviews

import (
"encoding/json"
Expand All @@ -9,6 +9,11 @@ func writePayload(w http.ResponseWriter, headers map[string]string, payload inte
setHeaders(w, headers)

w.WriteHeader(statusCode)

if payload == nil {
return nil
}

return json.NewEncoder(w).Encode(payload)
}

Expand Down
2 changes: 1 addition & 1 deletion api/views/errors.go → api/commonviews/errors.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package views
package commonviews

import (
"encoding/json"
Expand Down
2 changes: 1 addition & 1 deletion api/views/success.go → api/commonviews/success.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package views
package commonviews

import "net/http"

Expand Down
6 changes: 5 additions & 1 deletion cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

// @title 이웃집멍냥 API 문서
// @version 0.1.0
// @version 0.2.0
// @description 이웃집멍냥 백엔드 API 문서입니다.
// @termsOfService http://swagger.io/terms/

Expand All @@ -25,6 +25,10 @@ import (

// @host
// @BasePath /api

// @securityDefinitions.apiKey FirebaseAuth
// @in header
// @name Authorization
func main() {
app := firebaseinfra.NewFirebaseApp(configs.FirebaseCredentialsPath)
r := server.NewRouter(app)
Expand Down
1 change: 1 addition & 0 deletions db/migrations/000003_create_pets_table.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE IF EXISTS pets;
17 changes: 17 additions & 0 deletions db/migrations/000003_create_pets_table.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS pets (
id SERIAL PRIMARY KEY,
owner_id BIGINT NOT NULL,
name VARCHAR(30) NOT NULL,
pet_type VARCHAR(10) NOT NULL,
sex VARCHAR(10) NOT NULL,
neutered BOOLEAN NOT NULL,
breed VARCHAR(30) NOT NULL,
birth_date DATE NOT NULL,
weight_in_kg DECIMAL(5, 2) NOT NULL,
additional_note VARCHAR(500),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP
);

CREATE INDEX pets_owner_id_idx ON pets (owner_id);
8 changes: 8 additions & 0 deletions docker-compose-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ services:
- POSTGRES_DB=pets_next_door_api_test
volumes:
- pg_pets_next_door_api_db_test:/var/lib/postgresql/data
networks:
- pets_next_door_api_test
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
Expand All @@ -27,6 +29,12 @@ services:
command:
[ "-path", "/db/migrations", "-database", "postgresql://postgres:postgres@db_test:5432/pets_next_door_api_test?sslmode=disable", "up" ]
restart: on-failure
networks:
- pets_next_door_api_test

volumes:
pg_pets_next_door_api_db_test:

networks:
pets_next_door_api_test:
driver: bridge
6 changes: 6 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ services:
- POSTGRES_DB=pets_next_door_api_dev
volumes:
- pg_pets_next_door_api_db:/var/lib/postgresql/data
networks:
- pets_next_door_api_dev

volumes:
pg_pets_next_door_api_db:

networks:
pets_next_door_api_dev:
driver: bridge
1 change: 1 addition & 0 deletions internal/database/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func (db *DB) Flush() error {
var tableNames []string = []string{
"users",
"media",
"pets",
}

for _, tableName := range tableNames {
Expand Down
93 changes: 93 additions & 0 deletions internal/database/pet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package database

import "github.com/pet-sitter/pets-next-door-api/internal/models"

func (tx *Tx) CreatePet(pet *models.Pet) (*models.Pet, error) {
err := tx.QueryRow(`
INSERT INTO
pets
(
owner_id,
name,
pet_type,
sex,
neutered,
breed,
birth_date,
weight_in_kg,
created_at,
updated_at
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
RETURNING id, created_at, updated_at
`,
pet.OwnerID,
pet.Name,
pet.PetType,
pet.Sex,
pet.Neutered,
pet.Breed,
pet.BirthDate,
pet.WeightInKg,
).Scan(&pet.ID, &pet.CreatedAt, &pet.UpdatedAt)

if err != nil {
return nil, err
}

return pet, nil
}

func (tx *Tx) FindPetsByOwnerID(ownerID int) ([]models.Pet, error) {
var pets []models.Pet

rows, err := tx.Query(`
SELECT
id,
owner_id,
name,
pet_type,
sex,
neutered,
breed,
birth_date,
weight_in_kg,
created_at,
updated_at
FROM
pets
WHERE
owner_id = $1 AND
deleted_at IS NULL
`,
ownerID,
)
if err != nil {
return nil, err
}
defer rows.Close()

for rows.Next() {
var pet models.Pet

if err := rows.Scan(
&pet.ID,
&pet.OwnerID,
&pet.Name,
&pet.PetType,
&pet.Sex,
&pet.Neutered,
&pet.Breed,
&pet.BirthDate,
&pet.WeightInKg,
&pet.CreatedAt,
&pet.UpdatedAt,
); err != nil {
return nil, err
}

pets = append(pets, pet)
}

return pets, nil
}
18 changes: 18 additions & 0 deletions internal/models/pet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package models

import "github.com/pet-sitter/pets-next-door-api/internal/types"

type Pet struct {
ID int `field:"id"`
OwnerID int `field:"owner_id"`
Name string `field:"name"`
PetType types.PetType `field:"pet_type"`
Sex types.PetSex `field:"sex"`
Neutered bool `field:"neutered"`
Breed string `field:"breed"`
BirthDate string `field:"birth_date"`
WeightInKg float64 `field:"weight_in_kg"`
CreatedAt string `field:"created_at"`
UpdatedAt string `field:"updated_at"`
DeletedAt string `field:"deleted_at"`
}
15 changes: 4 additions & 11 deletions internal/server/auth_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"

"firebase.google.com/go/auth"
"github.com/pet-sitter/pets-next-door-api/api/commonviews"
"github.com/pet-sitter/pets-next-door-api/internal/configs"
kakaoinfra "github.com/pet-sitter/pets-next-door-api/internal/infra/kakao"
"github.com/pet-sitter/pets-next-door-api/internal/models"
Expand Down Expand Up @@ -52,32 +53,24 @@ func (h *authHandler) kakaoCallback(w http.ResponseWriter, r *http.Request) {

tokenView, err := kakaoinfra.FetchAccessToken(code)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
commonviews.Unauthorized(w, nil, err.Error())
return
}

userProfile, err := kakaoinfra.FetchUserProfile(tokenView.AccessToken)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
commonviews.Unauthorized(w, nil, err.Error())
return
}

ctx := r.Context()
authClient := ctx.Value(firebaseAuthClientKey).(*auth.Client)
customToken, err := authClient.CustomToken(ctx, fmt.Sprintf("%d", userProfile.ID))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
commonviews.Unauthorized(w, nil, err.Error())
return
}

fbUser, _ := authClient.GetUserByEmail(ctx, userProfile.KakaoAccount.Email)
if provider, ok := fbUser.CustomClaims["provider"]; ok {
if provider != models.FirebaseProviderTypeKakao {
http.Error(w, fmt.Sprintf("user already registered with another provider: %s", fbUser.ProviderID), http.StatusConflict)
return
}
}

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(kakaoCallbackResponse{
Expand Down
18 changes: 9 additions & 9 deletions internal/server/media_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"net/http"
"strings"

"github.com/pet-sitter/pets-next-door-api/api/views"
"github.com/pet-sitter/pets-next-door-api/api/commonviews"
webutils "github.com/pet-sitter/pets-next-door-api/internal/common"
"github.com/pet-sitter/pets-next-door-api/internal/media"
"github.com/pet-sitter/pets-next-door-api/internal/models"
Expand Down Expand Up @@ -38,17 +38,17 @@ type mediaView struct {
func (h *mediaHandler) findMediaByID(w http.ResponseWriter, r *http.Request) {
id, err := webutils.ParseIdFromPath(r, "id")
if err != nil || id <= 0 {
views.NotFound(w, nil, "invalid media ID")
commonviews.NotFound(w, nil, "invalid media ID")
return
}

media, err := h.mediaService.FindMediaByID(id)
if err != nil {
views.BadRequest(w, nil, err.Error())
commonviews.BadRequest(w, nil, err.Error())
return
}

views.OK(w, nil, mediaView{
commonviews.OK(w, nil, mediaView{
ID: media.ID,
MediaType: media.MediaType,
URL: media.URL,
Expand All @@ -67,29 +67,29 @@ func (h *mediaHandler) findMediaByID(w http.ResponseWriter, r *http.Request) {
// @Router /media/images [post]
func (h *mediaHandler) uploadImage(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(10 << 20); err != nil {
views.BadRequest(w, nil, err.Error())
commonviews.BadRequest(w, nil, err.Error())
return
}

file, header, err := r.FormFile("file")
if err != nil {
views.BadRequest(w, nil, err.Error())
commonviews.BadRequest(w, nil, err.Error())
return
}
defer file.Close()

if !isValidMimeType(header.Header.Get("Content-Type")) {
views.BadRequest(w, nil, "invalid MIME type; supported MIME types are: ["+supportedMimeTypeString()+"]")
commonviews.BadRequest(w, nil, "invalid MIME type; supported MIME types are: ["+supportedMimeTypeString()+"]")
return
}

res, err := h.mediaService.UploadMedia(file, models.IMAGE_MEDIA_TYPE, header.Filename)
if err != nil {
views.BadRequest(w, nil, err.Error())
commonviews.BadRequest(w, nil, err.Error())
return
}

views.Created(w,
commonviews.Created(w,
nil,
mediaView{
ID: res.ID,
Expand Down
2 changes: 2 additions & 0 deletions internal/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ func addRoutes(r *chi.Mux) {
r.Post("/status", userHandler.FindUserStatusByEmail)
r.Get("/me", userHandler.FindMyProfile)
r.Put("/me", userHandler.UpdateMyProfile)
r.Get("/me/pets", userHandler.FindMyPets)
r.Put("/me/pets", userHandler.AddMyPets)
})
})
}
Loading

0 comments on commit c5b0024

Please sign in to comment.