-
Notifications
You must be signed in to change notification settings - Fork 2
Support fastify #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support fastify #88
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| // Import the framework and instantiate it | ||
| import Fastify, { FastifyError } from "fastify"; | ||
| import { | ||
| serializerCompiler, | ||
| validatorCompiler, | ||
| ZodTypeProvider, | ||
| } from "fastify-type-provider-zod"; | ||
| import { pathMap } from "../../spec/zod"; | ||
| import { toRoutes } from "../../../src/fastify/zod"; | ||
| import { ZodError } from "zod"; | ||
| const fastify = Fastify({ logger: true }); | ||
|
|
||
| fastify.setValidatorCompiler(validatorCompiler); | ||
| fastify.setSerializerCompiler(serializerCompiler); | ||
| const server = fastify.withTypeProvider<ZodTypeProvider>(); | ||
| server.setErrorHandler<ZodError | FastifyError>((error, request, reply) => { | ||
| if (error instanceof ZodError) { | ||
| return reply | ||
| .status(400) | ||
| .type("application/json") | ||
| .send({ errorMessage: JSON.stringify(error.issues) }); | ||
| } | ||
| return reply | ||
| .status(error.statusCode ?? 500) | ||
| .type("application/json") | ||
| .send({ errorMessage: error.message }); | ||
| }); | ||
| const routes = toRoutes(pathMap); | ||
|
|
||
| // Define by using route object | ||
| server.route({ | ||
| ...routes["/users"]["get"], | ||
| handler: async (request, reply) => { | ||
| const page = request.query.page; | ||
| if (Number.isNaN(Number(page))) { | ||
| return reply.status(400).send({ errorMessage: "page is not a number" }); | ||
| } | ||
| return { userNames: [`page${page}#user1`] }; | ||
| }, | ||
| }); | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const _noExecution = () => { | ||
| // Or you can also define by using RouteShorthandMethod | ||
| server.get( | ||
| "/users", | ||
| { | ||
| schema: routes["/users"]["get"]["schema"], | ||
| }, | ||
| async (request) => { | ||
| { | ||
| // @ts-expect-error noexist is not defined in pathMap["/users"]["get"] | ||
| request.query.noexist; | ||
| } | ||
| const page = request.query.page; | ||
| return { userNames: [`page${page}#user1`] }; | ||
| }, | ||
| ); | ||
| }; | ||
|
|
||
| server.route({ | ||
| ...routes["/users"]["post"], | ||
| handler: async (request, reply) => { | ||
| const userName = request.body.userName; | ||
| return reply | ||
| .header("Content-Type", "application/json") | ||
| .send({ userId: userName + "#0" }); | ||
| }, | ||
| }); | ||
|
|
||
| server.route({ | ||
| ...routes["/users/:userId"]["get"], | ||
| handler: async (request) => { | ||
| const userId = request.params.userId; | ||
| return { userName: `user#${userId}` }; | ||
| }, | ||
| }); | ||
|
|
||
| (async () => { | ||
| try { | ||
| await fastify.listen({ port: 3000 }); | ||
| } catch (err) { | ||
| fastify.log.error(err); | ||
| process.exit(1); | ||
| } | ||
| })(); | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,79 @@ | ||||
| import JSONT from "../../../src/json"; | ||||
| import { unreachable } from "../../../src/utils"; | ||||
| import type FetchT from "../../../src/fetch"; | ||||
| import { PathMap } from "../../spec/zod"; | ||||
|
|
||||
| const fetchT = fetch as FetchT<typeof origin, PathMap>; | ||||
| const origin = "http://localhost:3000"; | ||||
| const headers = { "Content-Type": "application/json" } as const; | ||||
| const JSONT = JSON as JSONT; | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the unnecessary redeclaration of The Apply this diff to remove the constant declaration: -const JSONT = JSON as JSONT;Committable suggestion
Suggested change
ToolsBiome
|
||||
|
|
||||
| const main = async () => { | ||||
| { | ||||
| const path = `${origin}/users?page=1`; | ||||
| const method = "get"; | ||||
| const res = await fetchT(path, { method }); | ||||
| switch (res.status) { | ||||
| case 200: { | ||||
| // r is the response schema defined in pathMap["/users"]["get"].res["200"] | ||||
| const r = await res.json(); | ||||
| console.log(`${path}:${method} => ${r.userNames}`); | ||||
| break; | ||||
| } | ||||
| case 400: { | ||||
| // e is the response schema defined in pathMap["/users"]["get"].res["400"] | ||||
| const e = await res.json(); | ||||
| console.log(`${path}:${method} => ${e.errorMessage}`); | ||||
| break; | ||||
| } | ||||
| default: | ||||
| unreachable(res); | ||||
| } | ||||
| } | ||||
| { | ||||
| // case-insensitive method example | ||||
| await fetchT(`${origin}/users?page=1`, { method: "GET" }); | ||||
| } | ||||
|
|
||||
| { | ||||
| const path = `${origin}/users`; | ||||
| const method = "post"; | ||||
| const res = await fetchT(path, { | ||||
| method, | ||||
| headers, | ||||
| // body is the request schema defined in pathMap["/users"]["post"].body | ||||
| // stringify is same as JSON.stringify but with common information | ||||
| body: JSONT.stringify({ userName: "user1" }), | ||||
| }); | ||||
| if (res.ok) { | ||||
| // r is the response schema defined in pathMap["/users"]["post"].res["20X"] | ||||
| const r = await res.json(); | ||||
| console.log(`${path}:${method} => ${r.userId}`); | ||||
| console.log(res.headers.get("Content-Type")); | ||||
| } else { | ||||
| // e is the response schema defined in pathMap["/users"]["post"].res other than "20X" | ||||
| const e = await res.text(); | ||||
| console.log(`error:${path}:${method} => ${JSON.stringify(e)}`); | ||||
| console.log(res.status); | ||||
| } | ||||
| } | ||||
|
|
||||
| { | ||||
| // path parameter example | ||||
| // "/users/:userId" accepts `/users/${string}` pattern | ||||
| const path = `${origin}/users/1`; | ||||
| const method = "get"; | ||||
| const res = await fetchT(path, { method }); | ||||
| if (res.ok) { | ||||
| // r is the response schema defined in pathMap["/users/:userId"]["get"].res["20X"] | ||||
| const r = await res.json(); | ||||
| console.log(`${path}:${method} => ${r.userName}`); | ||||
| } else { | ||||
| // e is the response schema defined in pathMap["/users/:userId"]["get"].res other than "20X" | ||||
| const e = await res.json(); | ||||
| console.log(`${path}:${method} => ${e.errorMessage}`); | ||||
| } | ||||
| } | ||||
| }; | ||||
|
|
||||
| main(); | ||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the redundant block statement.
The standalone block statement at line range 51-54 is redundant and can be safely removed to simplify the code.
Apply this diff to remove the redundant block statement:
Committable suggestion
Tools
Biome