From f247d09ecb8a046c1a46af40c18a2162aee5c3a8 Mon Sep 17 00:00:00 2001 From: minkj1992 Date: Mon, 28 Mar 2022 21:55:28 +0900 Subject: [PATCH 1/2] feat: Add base http response --- application/consts.go | 16 ++++++++ application/controller/roomController.go | 30 +++++--------- application/response.go | 52 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 19 deletions(-) create mode 100644 application/response.go diff --git a/application/consts.go b/application/consts.go index d544d09..7e8cfe6 100644 --- a/application/consts.go +++ b/application/consts.go @@ -6,3 +6,19 @@ const ( // AuthCodeKey is a auth code url query parameter AuthCodeKey = "authcode" ) + +const ( + EntityNotFound = 400001 + + 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/roomController.go b/application/controller/roomController.go index 59c23b2..4e29266 100644 --- a/application/controller/roomController.go +++ b/application/controller/roomController.go @@ -71,7 +71,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 +93,7 @@ func (rc *roomController) GetAll() gin.HandlerFunc { UpdatedAt: room.UpdatedAt, }) } - c.JSON(http.StatusOK, listResponseRoom{Rooms: roomsResponse}) + application.SuccessResponse(c, listResponseRoom{Rooms: roomsResponse}) } } @@ -127,18 +127,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 } @@ -186,14 +184,12 @@ 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) { @@ -337,8 +333,7 @@ func (rc *roomController) Patch() 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 } @@ -381,8 +376,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 } @@ -435,8 +429,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 } @@ -472,8 +465,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 { diff --git a/application/response.go b/application/response.go new file mode 100644 index 0000000..ccd3667 --- /dev/null +++ b/application/response.go @@ -0,0 +1,52 @@ +package application + +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + +// JSONSuccessResponse ... +type JSONSuccessResponse struct { + Code int `json:"code" example: "200"` + Message string `json:"message" example: "Success"` + Data interface{} `json:"data"` +} + +// JSONBadResponse ... +type JSONBadResponse struct { + Code int `json:"code" example: "40101"` + Message string `json:"message" example: "Only master can access"` + Data interface{} `json:"data"` +} + +// JSONServerErrResponse ... +type JSONServerErrResponse struct { + Code int `json:"code" example: "500"` + Message string `json:"message" example: "Error database"` + Data interface{} `json:"data"` +} + +func SuccessResponse(c *gin.Context, data interface{}) { + c.JSON(http.StatusOK, JSONSuccessResponse{ + Code: http.StatusOK, + Message: "Success", + Data: data, + }) +} + +func FailResponse(c *gin.Context, code int, message string) { + if code == http.StatusInternalServerError { + c.JSON(code, JSONServerErrResponse{ + Code: code, + Data: nil, + Message: message, + }) + return + } + c.JSON(code, JSONBadResponse{ + Code: code, + Data: nil, + Message: message, + }) +} From 661cca608f35e68d76fddcad4d5701a2a947f6fd Mon Sep 17 00:00:00 2001 From: Minwook Je Date: Mon, 4 Apr 2022 21:55:35 +0900 Subject: [PATCH 2/2] update room api swagger and response format --- application/consts.go | 14 ++++- application/controller/alarmController.go | 1 + application/controller/roomController.go | 52 +++++++++-------- application/response.go | 36 ++++++++---- docs/docs.go | 69 ++++++++++++++++++++++- docs/swagger.json | 69 ++++++++++++++++++++++- docs/swagger.yaml | 43 +++++++++++++- infrastructure/configs/dev.yaml | 2 +- 8 files changed, 240 insertions(+), 46 deletions(-) diff --git a/application/consts.go b/application/consts.go index 7e8cfe6..19ff324 100644 --- a/application/consts.go +++ b/application/consts.go @@ -8,7 +8,19 @@ const ( ) const ( - EntityNotFound = 400001 + 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 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 4e29266..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 { @@ -93,7 +94,7 @@ func (rc *roomController) GetAll() gin.HandlerFunc { UpdatedAt: room.UpdatedAt, }) } - application.SuccessResponse(c, 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 { @@ -159,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) } } @@ -176,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 { @@ -193,7 +201,7 @@ func (rc *roomController) GetOrders() gin.HandlerFunc { 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 } @@ -210,7 +218,7 @@ func (rc *roomController) GetOrders() gin.HandlerFunc { Members: &members, TurnAccountID: room.TurnAccountID, } - c.JSON(http.StatusOK, res) + application.Ok(c, res) } } @@ -241,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 } @@ -262,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) } } @@ -326,8 +333,7 @@ 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 } @@ -339,11 +345,11 @@ func (rc *roomController) Patch() gin.HandlerFunc { 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 @@ -357,7 +363,7 @@ func (rc *roomController) Patch() gin.HandlerFunc { } res := patchResponseRoom{RoomID: room.ID} - c.JSON(http.StatusOK, res) + application.Ok(c, res) } } @@ -367,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 @@ -398,7 +404,7 @@ func (rc *roomController) Delete() gin.HandlerFunc { c.JSON(http.StatusBadRequest, err.Error()) return } - c.Status(http.StatusNoContent) + application.NoConent(c) } } @@ -444,7 +450,7 @@ func (rc *roomController) Join() gin.HandlerFunc { c.JSON(http.StatusUnauthorized, err.Error()) return } - c.Status(http.StatusCreated) + application.Created(c, nil) } } @@ -473,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 index ccd3667..1d2f81f 100644 --- a/application/response.go +++ b/application/response.go @@ -8,45 +8,57 @@ import ( // JSONSuccessResponse ... type JSONSuccessResponse struct { - Code int `json:"code" example: "200"` - Message string `json:"message" example: "Success"` + 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: "40101"` - Message string `json:"message" example: "Only master can access"` - Data interface{} `json:"data"` + 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"` - Data interface{} `json:"data"` + Code int `json:"code" example:"500"` + Message string `json:"message" example:"Error database"` } -func SuccessResponse(c *gin.Context, data interface{}) { +func Ok(c *gin.Context, data interface{}) { c.JSON(http.StatusOK, JSONSuccessResponse{ Code: http.StatusOK, - Message: "Success", + 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, - Data: nil, Message: message, }) return } c.JSON(code, JSONBadResponse{ Code: code, - Data: nil, 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: