diff --git a/application/consts.go b/application/consts.go index d544d09..19ff324 100644 --- a/application/consts.go +++ b/application/consts.go @@ -6,3 +6,31 @@ const ( // AuthCodeKey is a auth code url query parameter AuthCodeKey = "authcode" ) + +const ( + EntityNotFoundErr = 400001 + EmptyParameterErr = 400002 + InvalidRequestBodyErr = 400003 + CannotCreateErr = 400004 + TaskRoomPeriodFINCreateErr = 400005 + TaskMemberOnDutyCreateErr = 400006 + TaskMemberBefore1HRCreateErr = 400007 + TaskMemberBefore4HRCreateErr = 400008 + TaskMemberPostedDiaryCreateErr = 400009 + + OnlyMemberErr = 401001 + OnlyMasterErr = 401002 + OnlyMemberOrMasterErr = 401003 + + StatusInternalServerError = 500 // RFC 7231, 6.6.1 + StatusNotImplemented = 501 // RFC 7231, 6.6.2 + StatusBadGateway = 502 // RFC 7231, 6.6.3 + StatusServiceUnavailable = 503 // RFC 7231, 6.6.4 + StatusGatewayTimeout = 504 // RFC 7231, 6.6.5 + StatusHTTPVersionNotSupported = 505 // RFC 7231, 6.6.6 + StatusVariantAlsoNegotiates = 506 // RFC 2295, 8.1 + StatusInsufficientStorage = 507 // RFC 4918, 11.5 + StatusLoopDetected = 508 // RFC 5842, 7.2 + StatusNotExtended = 510 // RFC 2774, 7 + StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6 +) diff --git a/application/controller/alarmController.go b/application/controller/alarmController.go index 3723f31..393ea18 100644 --- a/application/controller/alarmController.go +++ b/application/controller/alarmController.go @@ -73,5 +73,6 @@ func (ac *alarmController) List() gin.HandlerFunc { }) } c.JSON(http.StatusOK, AlarmListResponse{Alarms: rep}) + } } diff --git a/application/controller/roomController.go b/application/controller/roomController.go index 59c23b2..13d7719 100644 --- a/application/controller/roomController.go +++ b/application/controller/roomController.go @@ -61,8 +61,9 @@ type listResponseRoom struct { // @Tags rooms // @Accept json // @Produce json -// @Success 200 {object} listResponseRoom -// @Failure 400 +// @Success 200 {object} application.JSONSuccessResponse{data=listResponseRoom,code=int,message=string} +// @Failure 400001 {object} application.JSONBadResponse{code=int,message=string} "EntityNotFoundErr" +// @Failure 500 {object} application.JSONServerErrResponse{code=int,message=string} // @Router /rooms [get] // @Security ApiKeyAuth func (rc *roomController) GetAll() gin.HandlerFunc { @@ -71,7 +72,7 @@ func (rc *roomController) GetAll() gin.HandlerFunc { rooms, err := rc.roomService.GetAllJoinedRooms(currentMember.ID) if err != nil { logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EntityNotFoundErr, err.Error()) return } roomsResponse := []responseRoom{} @@ -93,7 +94,7 @@ func (rc *roomController) GetAll() gin.HandlerFunc { UpdatedAt: room.UpdatedAt, }) } - c.JSON(http.StatusOK, listResponseRoom{Rooms: roomsResponse}) + application.Ok(c, listResponseRoom{Rooms: roomsResponse}) } } @@ -118,8 +119,11 @@ type detailResponseRoom struct { // @Accept json // @Produce json // @Param id path int true "교환일기방 ID" Format(uint) -// @Success 200 {object} detailResponseRoom -// @Failure 400 +// @Success 200 {object} application.JSONSuccessResponse{data=detailResponseRoom,code=int,message=string} +// @Failure 400001 {object} application.JSONBadResponse{code=int,message=string} "EntityNotFoundErr" +// @Failure 400002 {object} application.JSONBadResponse{code=int,message=string} "EmptyParameterErr" +// @Failure 401003 {object} application.JSONBadResponse{code=int,message=string} "OnlyMemberOrMasterErr" +// @Failure 500 {object} application.JSONServerErrResponse{code=int,message=string} // @Router /rooms/{id} [get] // @Security ApiKeyAuth func (rc *roomController) Get() gin.HandlerFunc { @@ -127,18 +131,16 @@ func (rc *roomController) Get() gin.HandlerFunc { currentMember := c.MustGet(application.CurrentMemberKey).(application.CurrentMemberDTO) roomID, err := application.ParseUint(c.Param("room_id")) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EmptyParameterErr, err.Error()) return } room, err := rc.roomService.Get(roomID, entity.JoinedOrder) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, err.Error()) + application.FailResponse(c, application.EntityNotFoundErr, err.Error()) return } if !room.IsAlreadyJoined(currentMember.ID) { - c.JSON(http.StatusUnauthorized, "Only member or master can access") + application.FailResponse(c, application.OnlyMemberOrMasterErr, "Only member or master can access") return } @@ -161,7 +163,7 @@ func (rc *roomController) Get() gin.HandlerFunc { UpdatedAt: room.UpdatedAt, IsMaster: room.IsMaster(currentMember.ID), } - c.JSON(http.StatusOK, res) + application.Ok(c, res) } } @@ -178,7 +180,11 @@ type roomOrderResponse struct { // @Produce json // @Param id path int true "교환일기방 ID" Format(uint) // @Success 200 {object} roomOrderResponse -// @Failure 400 +// @Success 200 {object} application.JSONSuccessResponse{data=detailResponseRoom,code=int,message=string} +// @Failure 400001 {object} application.JSONBadResponse{code=int,message=string} "EntityNotFoundErr" +// @Failure 400002 {object} application.JSONBadResponse{code=int,message=string} "EmptyParameterErr" +// @Failure 401003 {object} application.JSONBadResponse{code=int,message=string} "OnlyMemberOrMasterErr" +// @Failure 500 {object} application.JSONServerErrResponse{code=int,message=string} // @Router /rooms/{id}/orders [get] // @Security ApiKeyAuth func (rc *roomController) GetOrders() gin.HandlerFunc { @@ -186,18 +192,16 @@ func (rc *roomController) GetOrders() gin.HandlerFunc { currentMember := c.MustGet(application.CurrentMemberKey).(application.CurrentMemberDTO) roomID, err := application.ParseUint(c.Param("room_id")) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EmptyParameterErr, err.Error()) return } room, err := rc.roomService.Get(roomID, entity.DiaryOrder) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, err.Error()) + application.FailResponse(c, application.EntityNotFoundErr, err.Error()) return } if !room.IsAlreadyJoined(currentMember.ID) { - c.JSON(http.StatusUnauthorized, "Only member or master can access room orders") + application.FailResponse(c, application.OnlyMemberOrMasterErr, "Only member or master can access room orders") return } @@ -214,7 +218,7 @@ func (rc *roomController) GetOrders() gin.HandlerFunc { Members: &members, TurnAccountID: room.TurnAccountID, } - c.JSON(http.StatusOK, res) + application.Ok(c, res) } } @@ -245,14 +249,13 @@ func (rc *roomController) Post() gin.HandlerFunc { currentMember := c.MustGet(application.CurrentMemberKey).(application.CurrentMemberDTO) var req postRequestRoom if err := c.BindJSON(&req); err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.InvalidRequestBodyErr, err.Error()) return } room, err := rc.roomService.Create(currentMember.ID, req.Name, req.Code, req.Hint, req.Theme, req.Period) if err != nil { logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, err.Error()) + application.FailResponse(c, application.CannotCreateErr, err.Error()) return } @@ -266,12 +269,12 @@ func (rc *roomController) Post() gin.HandlerFunc { room.DueAt, ); err != nil { logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, err.Error()) + application.FailResponse(c, application.TaskRoomPeriodFINCreateErr, err.Error()) return } res := postResponseRoom{RoomID: room.ID} - c.JSON(http.StatusOK, res) + application.Ok(c, res) } } @@ -330,25 +333,23 @@ func (rc *roomController) Patch() gin.HandlerFunc { currentMember := c.MustGet(application.CurrentMemberKey).(application.CurrentMemberDTO) var req patchRequestRoom if err := c.BindJSON(&req); err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.InvalidRequestBodyErr, err.Error()) return } roomID, err := application.ParseUint(c.Param("room_id")) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EmptyParameterErr, err.Error()) return } room, err := rc.roomService.Get(roomID, entity.Ignore) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, err.Error()) + application.FailResponse(c, application.EntityNotFoundErr, err.Error()) return } + // TODO: 여기부터 처리할것 if !room.IsMaster(currentMember.ID) { c.JSON(http.StatusUnauthorized, "Only master can patch room") return @@ -362,7 +363,7 @@ func (rc *roomController) Patch() gin.HandlerFunc { } res := patchResponseRoom{RoomID: room.ID} - c.JSON(http.StatusOK, res) + application.Ok(c, res) } } @@ -372,7 +373,7 @@ func (rc *roomController) Patch() gin.HandlerFunc { // @Accept json // @Produce json // @Param id path int true "교환일기방 ID" -// @Success 204 +// @Success 204 "NO CONTENT" // @Failure 400 // @Router /rooms/{id} [delete] // @Security ApiKeyAuth @@ -381,8 +382,7 @@ func (rc *roomController) Delete() gin.HandlerFunc { currentMember := c.MustGet(application.CurrentMemberKey).(application.CurrentMemberDTO) roomID, err := application.ParseUint(c.Param("room_id")) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EmptyParameterErr, err.Error()) return } @@ -404,7 +404,7 @@ func (rc *roomController) Delete() gin.HandlerFunc { c.JSON(http.StatusBadRequest, err.Error()) return } - c.Status(http.StatusNoContent) + application.NoConent(c) } } @@ -435,8 +435,7 @@ func (rc *roomController) Join() gin.HandlerFunc { } roomID, err := application.ParseUint(c.Param("room_id")) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EmptyParameterErr, err.Error()) return } @@ -451,7 +450,7 @@ func (rc *roomController) Join() gin.HandlerFunc { c.JSON(http.StatusUnauthorized, err.Error()) return } - c.Status(http.StatusCreated) + application.Created(c, nil) } } @@ -472,8 +471,7 @@ func (rc *roomController) Leave() gin.HandlerFunc { currentMember := c.MustGet(application.CurrentMemberKey).(application.CurrentMemberDTO) roomID, err := application.ParseUint(c.Param("room_id")) if err != nil { - logger.Error(err.Error()) - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + application.FailResponse(c, application.EmptyParameterErr, err.Error()) return } if err := rc.roomService.LeaveRoom(roomID, currentMember.ID); err != nil { @@ -481,6 +479,6 @@ func (rc *roomController) Leave() gin.HandlerFunc { c.JSON(http.StatusBadRequest, err.Error()) return } - c.Status(http.StatusNoContent) + application.NoConent(c) } } diff --git a/application/response.go b/application/response.go new file mode 100644 index 0000000..1d2f81f --- /dev/null +++ b/application/response.go @@ -0,0 +1,64 @@ +package application + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +// JSONSuccessResponse ... +type JSONSuccessResponse struct { + Code uint `json:"code" example:"200"` + Message string `json:"message" example:"Ok"` + Data interface{} `json:"data"` +} + +// JSONBadResponse ... +type JSONBadResponse struct { + Code int `json:"code" example:"40001"` + Message string `json:"message" example:"4xx errors"` +} + +// JSONServerErrResponse ... +type JSONServerErrResponse struct { + Code int `json:"code" example:"500"` + Message string `json:"message" example:"Error database"` +} + +func Ok(c *gin.Context, data interface{}) { + c.JSON(http.StatusOK, JSONSuccessResponse{ + Code: http.StatusOK, + Message: "Ok", + Data: data, + }) +} + +func Created(c *gin.Context, data interface{}) { + c.JSON(http.StatusOK, JSONSuccessResponse{ + Code: http.StatusCreated, + Message: "Created", + Data: data, + }) +} + +func NoConent(c *gin.Context) { + c.JSON(http.StatusOK, JSONSuccessResponse{ + Code: http.StatusNoContent, + Message: "No Conent", + Data: c.Request.TLS.NegotiatedProtocolIsMutual, + }) +} + +func FailResponse(c *gin.Context, code int, message string) { + if code == http.StatusInternalServerError { + c.JSON(code, JSONServerErrResponse{ + Code: code, + Message: message, + }) + return + } + c.JSON(code, JSONBadResponse{ + Code: code, + Message: message, + }) +} diff --git a/docs/docs.go b/docs/docs.go index 87854f5..7ae8e92 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -394,11 +394,47 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/controller.listResponseRoom" + "allOf": [ + { + "$ref": "#/definitions/application.JSONSuccessResponse" + }, + { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": { + "$ref": "#/definitions/controller.listResponseRoom" + }, + "message": { + "type": "string" + } + } + } + ] } }, - "400": { - "description": "" + "400101": { + "description": "엔티티낫파운드", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/application.JSONBadResponse" + }, + { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } + } + ] + } } } }, @@ -921,6 +957,33 @@ const docTemplate = `{ } }, "definitions": { + "application.JSONBadResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 40001 + }, + "message": { + "type": "string", + "example": "4xx errors" + } + } + }, + "application.JSONSuccessResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 200 + }, + "data": {}, + "message": { + "type": "string", + "example": "Ok" + } + } + }, "controller.AlarmListResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 2fe7c48..8782b2f 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -387,11 +387,47 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/controller.listResponseRoom" + "allOf": [ + { + "$ref": "#/definitions/application.JSONSuccessResponse" + }, + { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "data": { + "$ref": "#/definitions/controller.listResponseRoom" + }, + "message": { + "type": "string" + } + } + } + ] } }, - "400": { - "description": "" + "400101": { + "description": "엔티티낫파운드", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/application.JSONBadResponse" + }, + { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + } + } + } + ] + } } } }, @@ -914,6 +950,33 @@ } }, "definitions": { + "application.JSONBadResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 40001 + }, + "message": { + "type": "string", + "example": "4xx errors" + } + } + }, + "application.JSONSuccessResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "example": 200 + }, + "data": {}, + "message": { + "type": "string", + "example": "Ok" + } + } + }, "controller.AlarmListResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 096bfda..eeec47b 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,5 +1,24 @@ basePath: /v1 definitions: + application.JSONBadResponse: + properties: + code: + example: 40001 + type: integer + message: + example: 4xx errors + type: string + type: object + application.JSONSuccessResponse: + properties: + code: + example: 200 + type: integer + data: {} + message: + example: Ok + type: string + type: object controller.AlarmListResponse: properties: alarms: @@ -479,9 +498,27 @@ paths: "200": description: OK schema: - $ref: '#/definitions/controller.listResponseRoom' - "400": - description: "" + allOf: + - $ref: '#/definitions/application.JSONSuccessResponse' + - properties: + code: + type: integer + data: + $ref: '#/definitions/controller.listResponseRoom' + message: + type: string + type: object + "400101": + description: 엔티티낫파운드 + schema: + allOf: + - $ref: '#/definitions/application.JSONBadResponse' + - properties: + code: + type: integer + message: + type: string + type: object security: - ApiKeyAuth: [] summary: List rooms diff --git a/infrastructure/configs/dev.yaml b/infrastructure/configs/dev.yaml index 1315962..27ae19b 100644 --- a/infrastructure/configs/dev.yaml +++ b/infrastructure/configs/dev.yaml @@ -3,7 +3,7 @@ db-config: port: 3306 user: "root" name: "voda" - password: "root" + password: "wpalsdnr1!" client: kakao: