Skip to content

Commit

Permalink
feat: implement Project Create API (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
kumachan-mis authored Feb 25, 2024
1 parent b3b9d5b commit ede8d3b
Show file tree
Hide file tree
Showing 29 changed files with 1,087 additions and 90 deletions.
1 change: 1 addition & 0 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func main() {
projectApi := api.NewProjectApi(projectUseCase)

router.POST("/api/projects/list", projectApi.HandleList)
router.POST("/api/projects/create", projectApi.HandleCreate)

err = router.Run(":8080")
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions docs/openapi/paths/_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
$ref: ./hello-world.yaml
/api/projects/list:
$ref: ./projects/list.yaml
/api/projects/create:
$ref: ./projects/create.yaml
29 changes: 29 additions & 0 deletions docs/openapi/paths/projects/create.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
post:
tags:
- Projects
operationId: create
summary: Create new project
requestBody:
content:
application/json:
schema:
$ref: ../../schemas/ProjectCreateRequest.yaml
responses:
"200":
description: OK - Returns newly created project
content:
application/json:
schema:
$ref: ../../schemas/ProjectCreateResponse.yaml
"400":
description: Bad Request - Invalid request
content:
application/json:
schema:
$ref: ../../schemas/ProjectCreateErrorResponse.yaml
"500":
description: Internal Server Error - Server error
content:
application/json:
schema:
$ref: ../../schemas/ApplicationErrorResponse.yaml
11 changes: 11 additions & 0 deletions docs/openapi/schemas/ProjectCreateErrorResponse.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type: object
description: Error Response Body for Project Create API
properties:
message:
type: string
description: Error message when request body format is invalid
example: unexpected EOF
user:
$ref: ./UserError.yaml
project:
$ref: ./ProjectWithoutAutofieldError.yaml
10 changes: 10 additions & 0 deletions docs/openapi/schemas/ProjectCreateRequest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type: object
description: Request Body for Project Create API
properties:
user:
$ref: ./User.yaml
project:
$ref: ./ProjectWithoutAutofield.yaml
required:
- user
- project
7 changes: 7 additions & 0 deletions docs/openapi/schemas/ProjectCreateResponse.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type: object
description: Response Body for Project Create API
properties:
project:
$ref: ./Project.yaml
required:
- project
15 changes: 15 additions & 0 deletions docs/openapi/schemas/ProjectWithoutAutofield.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type: object
description: Project object without auto-generated fields
properties:
name:
type: string
maxLength: 100
description: Project name
example: My Project
description:
type: string
maxLength: 400
description: Project description
example: This is my project
required:
- name
11 changes: 11 additions & 0 deletions docs/openapi/schemas/ProjectWithoutAutofieldError.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
type: object
description: Error Message for ProjectWithoutAutofield object
properties:
name:
type: string
description: Error message for project name
example: project name is required, but got ''
description:
type: string
description: Error message for project description
example: project description must be less than or equal to 400 characters
8 changes: 8 additions & 0 deletions docs/openapi/schemas/_index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ HelloWorldRequest:
$ref: ./HelloWorldRequest.yaml
HelloWorldResponse:
$ref: ./HelloWorldResponse.yaml
User:
$ref: ./User.yaml
UserError:
$ref: ./UserError.yaml
Project:
$ref: ./Project.yaml
ProjectWithoutAutofield:
$ref: ./ProjectWithoutAutofield.yaml
ProjectWithoutAutofieldError:
$ref: ./ProjectWithoutAutofieldError.yaml
ProjectListRequest:
$ref: ./ProjectListRequest.yaml
ProjectListResponse:
Expand Down
15 changes: 4 additions & 11 deletions internal/api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,11 @@ import (
"github.com/sirupsen/logrus"
)

func JsonBindErrorToResponseMessage(err error) string {
func JsonBindErrorToMessage(err error) string {
return "invalid request format"
}

func JsonBindErrorToResponseModel[ErrorModel any](err error, defaultModel ErrorModel) ErrorModel {
return defaultModel
}

func UseCaseErrorToResponseMessage[ErrorModel any](err *usecase.Error[ErrorModel]) string {
func UseCaseErrorToMessage[ErrorResponse any](err *usecase.Error[ErrorResponse]) string {
switch err.Code() {
case usecase.InvalidArgumentError:
return "invalid request value"
Expand All @@ -23,9 +19,6 @@ func UseCaseErrorToResponseMessage[ErrorModel any](err *usecase.Error[ErrorModel
}
}

func UseCaseErrorToResponseModel[ErrorModel any](err *usecase.Error[ErrorModel], defaultModel ErrorModel) ErrorModel {
if err.Model() == nil {
return defaultModel
}
return *err.Model()
func UseCaseErrorToResponse[ErrorResponse any](err *usecase.Error[ErrorResponse]) ErrorResponse {
return *err.Response()
}
48 changes: 39 additions & 9 deletions internal/api/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

type ProjectApi interface {
HandleList(c *gin.Context)
HandleCreate(c *gin.Context)
}

type projectApi struct {
Expand All @@ -24,30 +25,59 @@ func (api projectApi) HandleList(c *gin.Context) {
var request model.ProjectListRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, model.ProjectListErrorResponse{
Message: JsonBindErrorToResponseMessage(err),
User: JsonBindErrorToResponseModel(err, model.UserError{}),
Message: JsonBindErrorToMessage(err),
})
return
}

projects, err := api.usecase.ListProjects(request.User)
res, err := api.usecase.ListProjects(request)

if err != nil && err.Code() == usecase.InvalidArgumentError {
resErr := UseCaseErrorToResponse(err)
c.JSON(http.StatusBadRequest, model.ProjectListErrorResponse{
Message: UseCaseErrorToResponseMessage(err),
User: UseCaseErrorToResponseModel(err, model.UserError{}),
Message: UseCaseErrorToMessage(err),
User: resErr.User,
})
return
}

if err != nil {
c.JSON(http.StatusInternalServerError, model.ApplicationErrorResponse{
Message: UseCaseErrorToResponseMessage(err),
Message: UseCaseErrorToMessage(err),
})
return
}

c.JSON(http.StatusOK, model.ProjectListResponse{
Projects: projects,
})
c.JSON(http.StatusOK, res)
}

func (api projectApi) HandleCreate(c *gin.Context) {
var request model.ProjectCreateRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, model.ProjectCreateErrorResponse{
Message: JsonBindErrorToMessage(err),
})
return
}

res, err := api.usecase.CreateProject(request)

if err != nil && err.Code() == usecase.InvalidArgumentError {
resErr := UseCaseErrorToResponse(err)
c.JSON(http.StatusBadRequest, model.ProjectCreateErrorResponse{
Message: UseCaseErrorToMessage(err),
User: resErr.User,
Project: resErr.Project,
})
return
}

if err != nil {
c.JSON(http.StatusInternalServerError, model.ApplicationErrorResponse{
Message: UseCaseErrorToMessage(err),
})
return
}

c.JSON(http.StatusCreated, res)
}
Loading

0 comments on commit ede8d3b

Please sign in to comment.