Skip to content
CodeSook
CodeSook

07.Continue Employee Controller


เราจะมาทำ Employee Controller ที่เหลือให้ครบ

Get Routes

import { Effect } from "effect"
import * as S from "effect/Schema"
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver, validator } from "hono-openapi/effect"
import { ServicesRuntime } from "../../runtimes/index.js"
import { Branded, EmployeeWithRelationsSchema, Helpers } from "../../schema/index.js"
import { EmployeeServiceContext } from "../../services/employee/index.js"
const getByIdResponseSchema = EmployeeWithRelationsSchema.Schema.omit("deletedAt")
const getByIdDocs = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(getByIdResponseSchema),
},
},
description: "Get Employee by EmployeeId",
},
404: {
content: {
"application/json": {
schema: resolver(S.Struct({
message: S.String,
})),
},
},
description: "Get Employee by EmployeeId not found",
},
},
tags: ["Employee"],
})
const validateGetByIdRequest = validator("param", S.Struct({
employeeId: Branded.EmployeeIdFromString,
}))
const getManyResponseSchema = S.Array(EmployeeWithRelationsSchema.Schema.omit("deletedAt"))
const getManyDocs = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(getManyResponseSchema),
},
},
description: "Get Employees",
},
500: {
content: {
"application/json": {
schema: resolver(S.Struct({
message: S.String,
})),
},
},
description: "Get Employees Error",
},
},
tags: ["Employee"],
})
export function setupEmployeeGetRoutes() {
const app = new Hono()
app.get("/:employeeId", getByIdDocs, validateGetByIdRequest, async (c) => {
const { employeeId } = c.req.valid("param")
const parseResponse = Helpers.fromObjectToSchemaEffect(getByIdResponseSchema)
const program = EmployeeServiceContext.pipe(
Effect.andThen(svc => svc.findOneById(employeeId)),
Effect.andThen(parseResponse),
Effect.andThen(data => c.json(data, 200)),
Effect.catchTags({
FindEmployeeByIdError: () => Effect.succeed(c.json({ message: "findOneById error" }, 500)),
NoSuchElementException: () => Effect.succeed(c.json({ message: "not found employee for id" }, 404)),
ParseError: () => Effect.succeed(c.json({ message: "findOneById error" }, 500)),
}),
Effect.withSpan("GET /:employeeId.employee.controller"),
)
const result = await ServicesRuntime.runPromise(program)
return result
})
app.get("/", getManyDocs, async (c) => {
const parseResponse = Helpers.fromObjectToSchemaEffect(getManyResponseSchema)
const program = EmployeeServiceContext.pipe(
// ^? Effect.Effect<..., never, EmployeeServiceContext>
Effect.tap(() => Effect.log("start finding many employees")),
Effect.andThen(svc => svc.findMany()),
Effect.andThen(parseResponse),
Effect.andThen(data => c.json(data, 200)),
Effect.tap(() => Effect.log("test")),
Effect.catchTags({
FindManyEmployeeError: () => Effect.succeed(c.json({ message: "find many error" }, 500)),
ParseError: () => Effect.succeed(c.json({ message: "parse error" }, 500)),
}),
Effect.annotateLogs({ key: "annotate" }),
Effect.withLogSpan("test"),
Effect.withSpan("GET /.employee.controller /"),
)
const result = await ServicesRuntime.runPromise(program)
return result
})
return app
}

Post Routes

import { Effect } from "effect"
import * as S from "effect/Schema"
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver, validator } from "hono-openapi/effect"
import { ServicesRuntime } from "../../runtimes/index.js"
import { EmployeeSchema, Helpers } from "../../schema/index.js"
import { EmployeeServiceContext } from "../../services/employee/index.js"
const responseSchema = EmployeeSchema.Schema.omit("deletedAt")
const docs = describeRoute({
responses: {
201: {
content: {
"application/json": {
schema: resolver(responseSchema),
},
},
description: "Created Employee",
},
500: {
content: {
"application/json": {
schema: resolver(S.Struct({
message: S.String,
})),
},
},
description: "Created Employee",
},
},
tags: ["Employee"],
validateResponse: true,
})
const validateRequestBody = validator("json", EmployeeSchema.CreateSchema)
export function setupEmployeePostRoutes() {
const app = new Hono()
app.post("/", docs, validateRequestBody, async (c) => {
const body = c.req.valid("json")
const parseResponse = Helpers.fromObjectToSchemaEffect(responseSchema)
const program = EmployeeServiceContext.pipe(
Effect.andThen(svc => svc.create(body).pipe(
Effect.retry(
pipe(
Schedule.recurs(3),
Schedule.addDelay(() => Duration.seconds(10)),
),
),
)),
Effect.andThen(parseResponse),
Effect.andThen(data => c.json(data, 201)),
Effect.orElseSucceed(() => c.json({ message: "create failed" }, 500)),
Effect.withSpan("POST /.employee.controller"),
)
const result = await ServicesRuntime.runPromise(program)
return result
})
return app
}

Update Routes

import { Effect } from "effect"
import * as S from "effect/Schema"
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver, validator } from "hono-openapi/effect"
import { ServicesRuntime } from "../../runtimes/index.js"
import { Branded, EmployeeSchema, Helpers } from "../../schema/index.js"
import { EmployeeServiceContext } from "../../services/employee/index.js"
const updateEmployeeResponseSchema = EmployeeSchema.Schema.omit("deletedAt")
const updateEmployeeDocs = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(updateEmployeeResponseSchema),
},
},
description: "Update Employees",
},
500: {
content: {
"application/json": {
schema: resolver(updateEmployeeResponseSchema),
},
},
description: "Update Employees Error",
},
},
tags: ["Employee"],
})
const validateUpdateEmployeeRequestBody = validator("json", EmployeeSchema.UpdateSchema)
const validateUpdateEmployeeRequestParam = validator("param", S.Struct({
employeeId: Branded.EmployeeIdFromString,
}))
export function setupEmployeePutRoutes() {
const app = new Hono()
app.put("/:employeeId", updateEmployeeDocs, validateUpdateEmployeeRequestBody, validateUpdateEmployeeRequestParam, async (c) => {
const data = c.req.valid("json")
const { employeeId } = c.req.valid("param")
const parseResponse = Helpers.fromSchemaToObjectEffect(updateEmployeeResponseSchema)
const program = EmployeeServiceContext.pipe(
Effect.andThen(svc => svc.update(employeeId, data)),
Effect.andThen(parseResponse),
Effect.andThen(data => c.json(data, 200)),
Effect.orElseSucceed(() => c.json({ message: "update failed" }, 500)),
Effect.withSpan("PUT /.employee.controller"),
)
const result = await ServicesRuntime.runPromise(program)
return result
})
return app
}

Delete Routes

import { Effect } from "effect"
import * as S from "effect/Schema"
import { Hono } from "hono"
import { describeRoute } from "hono-openapi"
import { resolver, validator } from "hono-openapi/effect"
import { ServicesRuntime } from "../../runtimes/index.js"
import { Branded, EmployeeSchema, Helpers } from "../../schema/index.js"
import { EmployeeServiceContext } from "../../services/employee/index.js"
const deleteEmployeResponseSchema = EmployeeSchema.Schema.omit("deletedAt")
const deleteEmployeeDocs = describeRoute({
responses: {
200: {
content: {
"application/json": {
schema: resolver(deleteEmployeResponseSchema),
},
},
description: "Get Employee by EmployeeId",
},
},
tags: ["Employee"],
})
const validateDeleteEmployeeRequest = validator("param", S.Struct({
employeeId: Branded.EmployeeIdFromString,
}))
export function setupRoutes() {
const app = new Hono()
app.delete("/:employeeId", deleteEmployeeDocs, validateDeleteEmployeeRequest, async (c) => {
const { employeeId } = c.req.valid("param")
const parseResponse = Helpers.fromObjectToSchemaEffect(deleteEmployeResponseSchema)
const program = EmployeeServiceContext.pipe(
Effect.andThen(svc => svc.removeById(employeeId)),
Effect.andThen(parseResponse),
Effect.andThen(data => c.json(data, 200)),
Effect.orElseSucceed(() => c.json({ message: "delete failed" }, 500)),
Effect.withSpan("DELETE /:employeeId.employee.controller"),
)
const result = await ServicesRuntime.runPromise(program)
return result
})
return app
}