Skip to content

Commit cae5248

Browse files
committed
Fix examples
1 parent ebb77f7 commit cae5248

File tree

6 files changed

+74
-63
lines changed

6 files changed

+74
-63
lines changed

examples/misc/express/valibot/express.ts

+25-24
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ToHandlers, typed } from "@notainc/typed-api-spec/express/valibot";
66
const emptyMiddleware = (
77
req: express.Request,
88
res: express.Response,
9-
next: express.NextFunction,
9+
next: express.NextFunction
1010
) => next();
1111
type Handlers = ToHandlers<typeof pathMap>;
1212
const newApp = () => {
@@ -20,7 +20,7 @@ const newApp = () => {
2020
// const wApp = app as TRouter<typeof pathMap>;
2121
// ```
2222
const wApp = asAsync(typed(pathMap, app));
23-
wApp.get("/users", emptyMiddleware, (req, res) => {
23+
wApp.get("/users", emptyMiddleware, async (req, res) => {
2424
// eslint-disable-next-line no-constant-condition
2525
if (false) {
2626
// @ts-expect-error params is not defined because pathMap["/users"]["get"].params is not defined
@@ -29,41 +29,42 @@ const newApp = () => {
2929

3030
// validate method is available in res.locals
3131
// validate(req).query() is equals to pathMap["/users"]["get"].query.safeParse(req.query)
32-
const { data, error } = res.locals.validate(req).query();
33-
if (data !== undefined) {
34-
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["get"].res["200"]
35-
res.status(200).json({ userNames: [`page${data.page}#user1`] });
36-
} else {
32+
const r = await res.locals.validate(req).query();
33+
if (r.issues) {
3734
// res.status(400).json() accepts only the response schema defined in pathMap["/users"]["get"].res["400"]
38-
res.status(400).json({ errorMessage: error.toString() });
35+
return res.status(400).json({ errorMessage: r.issues.toString() });
3936
}
37+
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["get"].res["200"]
38+
return res.status(200).json({ userNames: [`page${r.value.page}#user1`] });
4039
});
41-
wApp.post("/users", (req, res) => {
42-
// validate(req).body() is equals to pathMap["/users"]["post"].body.safeParse(req.body)
43-
const { data, error } = res.locals.validate(req).body();
40+
41+
wApp.post("/users", async (req, res) => {
4442
{
4543
// Request header also can be validated
4644
res.locals.validate(req).headers();
4745
}
48-
if (data !== undefined) {
49-
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["post"].res["200"]
50-
res.status(200).json({ userId: data.userName + "#0" });
51-
} else {
46+
47+
// validate(req).body() is equals to pathMap["/users"]["post"].body.safeParse(req.body)
48+
const r = await res.locals.validate(req).body();
49+
if (r.issues) {
5250
// res.status(400).json() accepts only the response schema defined in pathMap["/users"]["post"].res["400"]
53-
res.status(400).json({ errorMessage: error.toString() });
51+
return res.status(400).json({ errorMessage: r.issues.toString() });
5452
}
53+
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["post"].res["200"]
54+
return res.status(200).json({ userId: r.value.userName + "#0" });
5555
});
5656

57-
const getUserHandler: Handlers["/users/:userId"]["get"] = (req, res) => {
58-
const { data: params, error } = res.locals.validate(req).params();
59-
60-
if (params !== undefined) {
61-
// res.status(200).json() accepts only the response schema defined in pathMap["/users/:userId"]["get"].res["200"]
62-
res.status(200).json({ userName: "user#" + params.userId });
63-
} else {
57+
const getUserHandler: Handlers["/users/:userId"]["get"] = async (
58+
req,
59+
res
60+
) => {
61+
const r = await res.locals.validate(req).params();
62+
if (r.issues) {
6463
// res.status(400).json() accepts only the response schema defined in pathMap["/users/:userId"]["get"].res["400"]
65-
res.status(400).json({ errorMessage: error.toString() });
64+
return res.status(400).json({ errorMessage: r.issues.toString() });
6665
}
66+
// res.status(200).json() accepts only the response schema defined in pathMap["/users/:userId"]["get"].res["200"]
67+
return res.status(200).json({ userName: "user#" + r.value.userId });
6768
};
6869
wApp.get("/users/:userId", getUserHandler);
6970

examples/misc/express/zod/express.ts

+25-24
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { asAsync } from "@notainc/typed-api-spec/express";
66
const emptyMiddleware = (
77
req: express.Request,
88
res: express.Response,
9-
next: express.NextFunction,
9+
next: express.NextFunction
1010
) => next();
1111
type Handlers = ToHandlers<typeof pathMap>;
1212
const newApp = () => {
@@ -20,7 +20,7 @@ const newApp = () => {
2020
// const wApp = app as TRouter<typeof pathMap>;
2121
// ```
2222
const wApp = asAsync(typed(pathMap, app));
23-
wApp.get("/users", emptyMiddleware, (req, res) => {
23+
wApp.get("/users", emptyMiddleware, async (req, res) => {
2424
// eslint-disable-next-line no-constant-condition
2525
if (false) {
2626
// @ts-expect-error params is not defined because pathMap["/users"]["get"].params is not defined
@@ -29,41 +29,42 @@ const newApp = () => {
2929

3030
// validate method is available in res.locals
3131
// validate(req).query() is equals to pathMap["/users"]["get"].query.safeParse(req.query)
32-
const { data, error } = res.locals.validate(req).query();
33-
if (data !== undefined) {
34-
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["get"].res["200"]
35-
res.status(200).json({ userNames: [`page${data.page}#user1`] });
36-
} else {
32+
const r = await res.locals.validate(req).query();
33+
if (r.issues) {
3734
// res.status(400).json() accepts only the response schema defined in pathMap["/users"]["get"].res["400"]
38-
res.status(400).json({ errorMessage: error.toString() });
35+
return res.status(400).json({ errorMessage: r.issues.toString() });
3936
}
37+
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["get"].res["200"]
38+
return res.status(200).json({ userNames: [`page${r.value.page}#user1`] });
4039
});
41-
wApp.post("/users", (req, res) => {
42-
// validate(req).body() is equals to pathMap["/users"]["post"].body.safeParse(req.body)
43-
const { data, error } = res.locals.validate(req).body();
40+
41+
wApp.post("/users", async (req, res) => {
4442
{
4543
// Request header also can be validated
4644
res.locals.validate(req).headers();
4745
}
48-
if (data !== undefined) {
49-
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["post"].res["200"]
50-
res.status(200).json({ userId: data.userName + "#0" });
51-
} else {
46+
47+
// validate(req).body() is equals to pathMap["/users"]["post"].body.safeParse(req.body)
48+
const r = await res.locals.validate(req).body();
49+
if (r.issues) {
5250
// res.status(400).json() accepts only the response schema defined in pathMap["/users"]["post"].res["400"]
53-
res.status(400).json({ errorMessage: error.toString() });
51+
return res.status(400).json({ errorMessage: r.issues.toString() });
5452
}
53+
// res.status(200).json() accepts only the response schema defined in pathMap["/users"]["post"].res["200"]
54+
return res.status(200).json({ userId: r.value.userName + "#0" });
5555
});
5656

57-
const getUserHandler: Handlers["/users/:userId"]["get"] = (req, res) => {
58-
const { data: params, error } = res.locals.validate(req).params();
59-
60-
if (params !== undefined) {
61-
// res.status(200).json() accepts only the response schema defined in pathMap["/users/:userId"]["get"].res["200"]
62-
res.status(200).json({ userName: "user#" + params.userId });
63-
} else {
57+
const getUserHandler: Handlers["/users/:userId"]["get"] = async (
58+
req,
59+
res
60+
) => {
61+
const r = await res.locals.validate(req).params();
62+
if (r.issues) {
6463
// res.status(400).json() accepts only the response schema defined in pathMap["/users/:userId"]["get"].res["400"]
65-
res.status(400).json({ errorMessage: error.toString() });
64+
return res.status(400).json({ errorMessage: r.issues.toString() });
6665
}
66+
// res.status(200).json() accepts only the response schema defined in pathMap["/users/:userId"]["get"].res["200"]
67+
return res.status(200).json({ userName: "user#" + r.value.userId });
6768
};
6869
wApp.get("/users/:userId", getUserHandler);
6970

examples/misc/fastify/zod/fastify.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ const routes = toRoutes(pathMap);
3131
server.route({
3232
...routes["/users"]["get"],
3333
handler: async (request, reply) => {
34-
const page = request.query.page;
34+
type Query = { page: string };
35+
const { page } = request.query as Query;
3536
if (Number.isNaN(Number(page))) {
3637
return reply.status(400).send({ errorMessage: "page is not a number" });
3738
}
@@ -52,16 +53,18 @@ const _noExecution = () => {
5253
// @ts-expect-error noexist is not defined in pathMap["/users"]["get"]
5354
request.query.noexist;
5455
}
55-
const page = request.query.page;
56+
type Query = { page: string };
57+
const { page } = request.query as Query;
5658
return { userNames: [`page${page}#user1`] };
57-
},
59+
}
5860
);
5961
};
6062

6163
server.route({
6264
...routes["/users"]["post"],
6365
handler: async (request, reply) => {
64-
const userName = request.body.userName;
66+
type Body = { userName: string };
67+
const { userName } = request.body as Body;
6568
return reply
6669
.header("Content-Type", "application/json")
6770
.send({ userId: userName + "#0" });
@@ -71,7 +74,8 @@ server.route({
7174
server.route({
7275
...routes["/users/:userId"]["get"],
7376
handler: async (request) => {
74-
const userId = request.params.userId;
77+
type Params = { userId: string };
78+
const { userId } = request.params as Params;
7579
return { userName: `user#${userId}` };
7680
},
7781
});

examples/misc/simple/withValidation.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { newZodValidator, ZodApiEndpoints } from "@notainc/typed-api-spec/zod";
21
import { withValidation } from "@notainc/typed-api-spec/fetch";
32
import { z } from "zod";
43
import { SpecValidatorError } from "@notainc/typed-api-spec/fetch";
4+
import { newSSValidator, SSApiEndpoints } from "@notainc/typed-api-spec/ss";
55

66
const GITHUB_API_ORIGIN = "https://api.github.com";
77

@@ -12,24 +12,24 @@ const spec = {
1212
responses: { 200: { body: z.object({ names: z.string().array() }) } },
1313
},
1414
},
15-
} satisfies ZodApiEndpoints;
15+
} satisfies SSApiEndpoints;
1616
const spec2 = {
1717
"/repos/:owner/:repo/topics": {
1818
get: {
1919
// Invalid response schema
2020
responses: { 200: { body: z.object({ noexist: z.string() }) } },
2121
},
2222
},
23-
} satisfies ZodApiEndpoints;
23+
} satisfies SSApiEndpoints;
2424

2525
const main = async () => {
2626
{
2727
// const fetchT = fetch as FetchT<typeof GITHUB_API_ORIGIN, Spec>;
28-
const { req: reqValidator, res: resValidator } = newZodValidator(spec);
28+
const { req: reqValidator, res: resValidator } = newSSValidator(spec);
2929
const fetchWithV = withValidation(fetch, spec, reqValidator, resValidator);
3030
const response = await fetchWithV(
3131
`${GITHUB_API_ORIGIN}/repos/nota/typed-api-spec/topics?page=1`,
32-
{ headers: { Accept: "application/vnd.github+json" } },
32+
{ headers: { Accept: "application/vnd.github+json" } }
3333
);
3434
if (!response.ok) {
3535
const { message } = await response.json();
@@ -41,16 +41,16 @@ const main = async () => {
4141

4242
{
4343
// const fetchT = fetch as FetchT<typeof GITHUB_API_ORIGIN, Spec>;
44-
const { req: reqValidator, res: resValidator } = newZodValidator(spec2);
44+
const { req: reqValidator, res: resValidator } = newSSValidator(spec2);
4545
const fetchWithV = withValidation(fetch, spec2, reqValidator, resValidator);
4646
try {
4747
await fetchWithV(
4848
`${GITHUB_API_ORIGIN}/repos/nota/typed-api-spec/topics?page=1`,
49-
{ headers: { Accept: "application/vnd.github+json" } },
49+
{ headers: { Accept: "application/vnd.github+json" } }
5050
);
5151
} catch (e) {
5252
if (e instanceof SpecValidatorError) {
53-
console.log("error thrown", e.error);
53+
console.log("error thrown", e);
5454
} else {
5555
throw e;
5656
}

examples/misc/spec/zod.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { SSApiEndpoints, ToApiEndpoints } from "@notainc/typed-api-spec/ss";
12
import { z } from "zod";
2-
import { ToApiEndpoints, ZodApiEndpoints } from "@notainc/typed-api-spec/zod";
33

44
const JsonHeader = z.union([
55
z.object({ "content-type": z.literal("application/json") }),
@@ -42,5 +42,5 @@ export const pathMap = {
4242
},
4343
},
4444
},
45-
} satisfies ZodApiEndpoints;
45+
} satisfies SSApiEndpoints;
4646
export type PathMap = ToApiEndpoints<typeof pathMap>;

pkgs/typed-api-spec/package.json

+5
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@
132132
"types": "./dist/valibot/openapi.d.ts",
133133
"require": "./dist/valibot/openapi.js",
134134
"import": "./dist/valibot/openapi.mjs"
135+
},
136+
"./ss": {
137+
"types": "./dist/ss/index.d.ts",
138+
"require": "./dist/ss/index.js",
139+
"import": "./dist/ss/index.mjs"
135140
}
136141
},
137142
"main": "./dist/index.js",

0 commit comments

Comments
 (0)