Skip to content
CodeSook
CodeSook

18. Overtime Controllers


File and Folder structure

src
4 collapsed lines
├── configure
│ └── openapi
│ ├── setup-openapi.ts
│ └── setup-scalar-docs.ts
├── controllers
7 collapsed lines
│ ├── employees
│ │ ├── delete.ts
│ │ ├── get.ts
│ │ ├── index.ts
│ │ ├── post.ts
│ │ └── put.ts
│ ├── healthz.ts
│ └── overtimes
│ ├── get.ts
│ ├── index.ts
│ └── post.ts
45 collapsed lines
├── global.d.ts
├── index.ts
├── repositories
│ ├── employees
│ │ ├── creates.ts
│ │ ├── finds.ts
│ │ ├── index.ts
│ │ ├── removes.ts
│ │ └── updates.ts
│ ├── overtimes
│ │ ├── creates.ts
│ │ ├── finds.ts
│ │ ├── index.ts
│ │ ├── removes.ts
│ │ └── updates.ts
│ └── prisma.ts
├── schema
│ ├── branded.ts
│ ├── employee.ts
│ ├── employeeWithRelations.ts
│ ├── general.ts
│ ├── helpers.ts
│ ├── index.ts
│ ├── overtime.ts
│ └── overtimeWithRelations.ts
├── services
│ ├── employee
│ │ ├── create.ts
│ │ ├── finds.ts
│ │ ├── index.ts
│ │ ├── removes.ts
│ │ └── updates.ts
│ └── overtime
│ ├── creates.ts
│ ├── finds.ts
│ ├── index.ts
│ ├── removes.ts
│ └── updates.ts
└── types
├── repositories
│ ├── employee.ts
│ └── overtime.ts
└── services
├── employee.ts
└── overtime.ts

POST /

src/controllers/overtimes/post.ts
src/controllers/overtimes/post.ts
import type { OvertimeService } from "../../types/services/overtime.js"
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver, validator } from "hono-openapi/effect"
import { OvertimeSchema } from "../../schema/index.js"
const createOvertimeResponseSchema = OvertimeSchema.Schema.omit("deletedAt")
const createOvertimeDocs = describeRoute({
responses: {
201: {
content: {
"application/json": {
schema: resolver(createOvertimeResponseSchema),
},
},
description: "Get Employee by EmployeeId",
},
},
tags: ["Overtime"],
})
const createOvertimeValidateRequest = validator("json", OvertimeSchema.CreateSchema)
export function setupPosts(overtimeService: OvertimeService) {
const app = new Hono()
app.post("/", createOvertimeDocs, createOvertimeValidateRequest, async (c) => {
const body = c.req.valid("json")
const overtime = await overtimeService.create(body)
const resObj = createOvertimeResponseSchema.make(overtime)
return c.json(resObj, 201)
})
return app
}

GET /

src/controllers/overtimes/get.ts
src/controllers/overtimes/get.ts
import type { EmployeeService } from "../../types/services/employee.js"
import type { OvertimeService } from "../../types/services/overtime.js"
import * as S from "effect/Schema"
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver, validator } from "hono-openapi/effect"
import { Branded, EmployeeSchema, Helpers, OvertimeWithRelationsSchema } from "../../schema/index.js"
const getManyResponseSchema = S.Array(OvertimeWithRelationsSchema.Schema.omit("deletedAt"))
const getManyDocs = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(getManyResponseSchema),
},
},
description: "Get Overtimes",
},
},
tags: ["Overtime"],
})
const getByIdResponseSchema = OvertimeWithRelationsSchema.Schema.omit("deletedAt")
const getByIdDocs = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(getByIdResponseSchema),
},
},
description: "Get Overtime by OvertimeId",
},
404: {
content: {
"application/json": {
schema: resolver(S.Struct({
message: S.Literal("Not Found").pipe(S.optional, S.withConstructorDefault(() => "Not Found" as const)),
})),
},
},
description: "Overtime Not Found",
},
},
tags: ["Overtime"],
})
const validateGetByIdRequest = validator("param", S.Struct({
overtimeId: Branded.OvertimeIdFromString,
}))
const getOvertimeByEmployeeIdResponseSchema = OvertimeWithRelationsSchema.SchemaArray
const getOvertimeByEmployeeIdDoc = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(getOvertimeByEmployeeIdResponseSchema),
},
},
description: "Get Overtime by EmployeeId",
},
},
tags: ["Overtime"],
})
const getOvertimeByEmployeeIdValidateRequest = validator("param", S.Struct({
employeeId: Branded.EmployeeIdFromString,
}))
const getOvertimeByDepartmentNameDoc = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(getOvertimeByEmployeeIdResponseSchema),
},
},
description: "Get Overtime by EmployeeId",
},
},
tags: ["Overtime"],
})
const getOvertimeByDepartmentNameValidateRequest = validator("param", S.Struct({
department: EmployeeSchema.Schema.fields.department,
}))
const summaryResponseSchema = S.Struct({
hoursWorked: S.Number.annotations({ jsonSchema: { example: 8.5, type: "number" } }),
})
const overtimeSummaryForEmployeeDoc = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(summaryResponseSchema),
},
},
description: "Get Overtime by EmployeeId",
},
},
tags: ["Overtime"],
})
const validateOvertimeSummaryByEmployeeIdRequest = {
param: validator("param", S.Struct({
employeeId: Branded.EmployeeIdFromString,
})),
query: validator("query", S.Struct({
end: S.Date.annotations({ jsonSchema: { example: "2021-01-02", format: "date", type: "string" } }),
start: S.Date.annotations({ jsonSchema: { example: "2021-01-01", format: "date", type: "string" } }),
})),
}
const overtimeSummaryForDepartmentDoc = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(summaryResponseSchema),
},
},
description: "Get Overtime by Department",
},
},
tags: ["Overtime"],
})
const validateOvertimeSummaryByDepartmentRequest = {
param: validator("param", S.Struct({
department: EmployeeSchema.Schema.fields.department,
})),
query: validator("query", S.Struct({
end: S.Date.annotations({ jsonSchema: { example: "2021-01-02", format: "date", type: "string" } }),
start: S.Date.annotations({ jsonSchema: { example: "2021-01-01", format: "date", type: "string" } }),
})),
}
export function setupGet(overtimeService: OvertimeService, employeeService: EmployeeService) {
const app = new Hono()
app.get("/", getManyDocs, async (c) => {
const overtimes = await overtimeService.findMany()
const resObj = Helpers.fromObjectToSchema(getManyResponseSchema)(overtimes)
return c.json(resObj, 200)
})
app.get("/:overtimeId", getByIdDocs, validateGetByIdRequest, async (c) => {
const { overtimeId } = c.req.valid("param")
const overtime = await overtimeService.findById(overtimeId)
if (overtime === null)
return c.json({ message: "Not Found" }, 404)
return c.json(getByIdResponseSchema.make(overtime), 200)
})
app.get("/employees/:employeeId", getOvertimeByEmployeeIdDoc, getOvertimeByEmployeeIdValidateRequest, async (c) => {
const { employeeId } = c.req.valid("param")
const employeeWithRelations = await employeeService.findOneById(employeeId)
if (employeeWithRelations === null)
return c.json({ message: "Not Found" }, 404)
return c.json(Helpers.fromObjectToSchema(getOvertimeByEmployeeIdResponseSchema)(employeeWithRelations.overtimes), 200)
})
app.get("/department/:department", getOvertimeByDepartmentNameDoc, getOvertimeByDepartmentNameValidateRequest, async (c) => {
const { department } = c.req.valid("param")
const overtimes = await overtimeService.findByDepartmentName(department)
const resObj = Helpers.fromObjectToSchema(getOvertimeByEmployeeIdResponseSchema)(overtimes)
return c.json(resObj, 200)
})
app.get("/employees/:employeeId/summary", overtimeSummaryForEmployeeDoc, validateOvertimeSummaryByEmployeeIdRequest.param, validateOvertimeSummaryByEmployeeIdRequest.query, async (c) => {
const { employeeId } = c.req.valid("param")
const { end, start } = c.req.valid("query")
const ot = await overtimeService.summaryByEmployeeId({
dateRange: { end, start },
employeeId,
})
return c.json(summaryResponseSchema.make(ot), 200)
})
app.get("/department/:department/summary", overtimeSummaryForDepartmentDoc, validateOvertimeSummaryByDepartmentRequest.param, validateOvertimeSummaryByDepartmentRequest.query, async (c) => {
const { department } = c.req.valid("param")
const { end, start } = c.req.valid("query")
const ot = await overtimeService.summaryByDepartment({
dateRange: { end, start },
department,
})
return c.json(summaryResponseSchema.make(ot), 200)
})
return app
}

PUT and DELETE

ไม่ได้มีใน requirements ใครจะทำก็ลอง implement ดูได้นะ

exports controllers

เราจะมาทำ function ที่เอา Routes มารวมกัน แบบนี้

src/controllers/overtimes/index.ts
src/controllers/overtimes/index.ts
import type { EmployeeService } from "../../types/services/employee.js"
import type { OvertimeService } from "../../types/services/overtime.js"
import { Hono } from "hono"
import * as Gets from "./get.js"
import * as Posts from "./post.js"
export function setupOvertimesRoutes(overtimeService: OvertimeService, employeeService: EmployeeService) {
const app = new Hono()
app.route("/", Posts.setupPosts(overtimeService))
app.route("/", Gets.setupGet(overtimeService, employeeService))
return app
}

assign group to overtime controllers

src/index.ts
src/index.ts
32 collapsed lines
import { config } from "@dotenvx/dotenvx"
import { serve } from "@hono/node-server"
import { Hono } from "hono"
import { setupOpenApi } from "./configure/openapi/setup-openapi.js"
import { setupScalarDocs } from "./configure/openapi/setup-scalar-docs.js"
import * as EmployeeControllers from "./controllers/employees/index.js"
import healthzApp from "./controllers/healthz.js"
import * as OvertimeControllers from "./controllers/overtimes/index.js"
import initEmployeeRepository from "./repositories/employees/index.js"
import { initOvertimeRepository } from "./repositories/overtimes/index.js"
import prismaClient from "./repositories/prisma.js"
import { initEmployeeService } from "./services/employee/index.js"
import { initOvertimeService } from "./services/overtime/index.js"
config()
const app = new Hono()
setupOpenApi(app)
app.route("/docs", setupScalarDocs())
app.route("/healthz", healthzApp)
const employeeRepository = initEmployeeRepository(prismaClient)
const employeeService = initEmployeeService(employeeRepository)
app.route("/employees", EmployeeControllers.setupEmployeeRoutes(employeeService))
app.get("/", (c) => {
return c.text("Home")
})
const overtimeRepository = initOvertimeRepository(prismaClient)
const overtimeService = initOvertimeService(overtimeRepository)
app.route("/overtimes", OvertimeControllers.setupOvertimesRoutes(overtimeService, employeeService))
7 collapsed lines
const port = 3000
console.log(`Server is running on http://localhost:${port}`)
serve({
fetch: app.fetch,
port,
})

ลองเปิด Scalar ดู

ot1