Skip to content

Commit 062598e

Browse files
committed
Fix validation
1 parent 13c9871 commit 062598e

File tree

9 files changed

+149
-178
lines changed

9 files changed

+149
-178
lines changed

pkgs/typed-api-spec/.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const dRef = ["src/index.ts", "misc/**/*"];
1+
const dRef = ["src/index.ts", "misc/**/*", "**/*.test.ts"];
22
const depRules = [
33
{
44
module: "src/express",

pkgs/typed-api-spec/src/core/spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ParseUrlParams } from "./url";
22
import { ClientResponse, StatusCode } from "./hono-types";
33
import { C } from "../compile-error-utils";
44
import { JSONSchema7 } from "json-schema";
5+
import { StandardSchemaV1 } from "@standard-schema/spec";
56

67
/**
78
* { // ApiEndpoints
@@ -29,13 +30,15 @@ export type CaseInsensitive<S extends string> = S | Uppercase<S> | Lowercase<S>;
2930
export type CaseInsensitiveMethod = Method | Uppercase<Method>;
3031
export const isMethod = (x: unknown): x is Method =>
3132
Method.includes(x as Method);
32-
export interface MethodInvalidError {
33+
export interface MethodInvalidError extends StandardSchemaV1.Issue {
3334
error: "MethodInvalid";
3435
actual: string;
36+
message: string;
3537
}
3638
export const newMethodInvalidError = (method: string): MethodInvalidError => ({
3739
error: "MethodInvalid",
3840
actual: method,
41+
message: `MethodInvalid: ${method}`,
3942
});
4043

4144
export type ApiEndpoint = Partial<Record<Method, ApiSpec>>;

pkgs/typed-api-spec/src/core/validator/request.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,27 @@ export type SpecValidatorGeneratorInput<
5656
headers: Record<string, string | string[] | undefined>;
5757
};
5858

59-
export const runSpecValidator = (validators: AnySpecValidator | undefined) => {
60-
const newD = () =>
61-
({ value: undefined }) as StandardSchemaV1.SuccessResult<undefined>;
62-
return {
63-
params: validators?.params?.() ?? newD(),
64-
query: validators?.query?.() ?? newD(),
65-
body: validators?.body?.() ?? newD(),
66-
headers: validators?.headers?.() ?? newD(),
67-
};
59+
export const runSpecValidator = async (
60+
validators: AnySpecValidator,
61+
errorHandler: (
62+
reason: keyof AnySpecValidator | "preCheck",
63+
errors: Readonly<StandardSchemaV1.Issue[]>,
64+
) => void,
65+
) => {
66+
const params = await validators?.params?.();
67+
if (params?.issues) {
68+
errorHandler("params", params.issues);
69+
}
70+
const query = await validators?.query?.();
71+
if (query?.issues) {
72+
errorHandler("query", query.issues);
73+
}
74+
const body = await validators?.body?.();
75+
if (body?.issues) {
76+
errorHandler("body", body.issues);
77+
}
78+
const headers = await validators?.headers?.();
79+
if (headers?.issues) {
80+
errorHandler("headers", headers.issues);
81+
}
6882
};
Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
1-
import {
2-
AnyResponse,
3-
ApiSpecResponseKey,
4-
apiSpecResponseKeys,
5-
Method,
6-
} from "../spec";
7-
import { StatusCode } from "../hono-types";
8-
import { Result } from "../../utils";
9-
import { AnyValidator, ValidatorInputError } from "./validate";
1+
import { AnyResponse, ApiSpecResponseKey, apiSpecResponseKeys } from "../spec";
2+
import { AnyValidator } from "./validate";
103
import { StandardSchemaV1 } from "@standard-schema/spec";
114

125
export const listDefinedResponseApiSpecKeys = <Response extends AnyResponse>(
@@ -27,20 +20,24 @@ export type ResponseSpecValidator<
2720
export type AnyResponseSpecValidator = Partial<
2821
ResponseSpecValidator<AnyValidator, AnyValidator>
2922
>;
30-
export const runResponseSpecValidator = (
31-
r: Result<AnyResponseSpecValidator, ValidatorInputError>,
23+
export const runResponseSpecValidator = async (
24+
validators: AnyResponseSpecValidator,
25+
errorHandler: (
26+
reason: keyof AnyResponseSpecValidator | "preCheck",
27+
errors: Readonly<StandardSchemaV1.Issue[]>,
28+
) => void,
3229
) => {
33-
const newD = () =>
34-
({ value: undefined }) as StandardSchemaV1.SuccessResult<undefined>;
35-
return {
36-
// TODO: スキーマが間違っていても、bodyのvalidatorがなぜか定義されていない
37-
preCheck: r.error,
38-
body: r.data?.body?.() ?? newD(),
39-
headers: r.data?.headers?.() ?? newD(),
40-
};
30+
const body = await validators?.body?.();
31+
if (body?.issues) {
32+
errorHandler("body", body.issues);
33+
}
34+
const headers = await validators?.headers?.();
35+
if (headers?.issues) {
36+
errorHandler("headers", headers.issues);
37+
}
4138
};
4239

43-
export type ResponseSpecValidatorGeneratorRawInput<
40+
export type ResponseSpecValidatorGeneratorInput<
4441
Path extends string,
4542
M extends string,
4643
SC extends number,
@@ -51,14 +48,3 @@ export type ResponseSpecValidatorGeneratorRawInput<
5148
body?: unknown;
5249
headers: Record<string, string | string[] | undefined>;
5350
};
54-
export type ResponseSpecValidatorGeneratorInput<
55-
Path extends string,
56-
M extends Method,
57-
SC extends StatusCode,
58-
> = {
59-
path: Path;
60-
method: M;
61-
statusCode: SC;
62-
body?: unknown;
63-
headers: Record<string, string | string[] | undefined>;
64-
};

pkgs/typed-api-spec/src/core/validator/validate.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ import {
2424
SpecValidatorGeneratorInput,
2525
SpecValidatorGeneratorRawInput,
2626
} from "./request";
27-
import type { StandardSchemaV1 as SS } from "@standard-schema/spec";
27+
import type {
28+
StandardSchemaV1 as SS,
29+
StandardSchemaV1,
30+
} from "@standard-schema/spec";
2831
import {
2932
listDefinedResponseApiSpecKeys,
3033
ResponseSpecValidator,
31-
ResponseSpecValidatorGeneratorRawInput,
34+
ResponseSpecValidatorGeneratorInput,
3235
} from "./response";
3336
import { StatusCode } from "../hono-types";
3437
export type SSResult<Data> = SS.Result<Data> | Promise<SS.Result<Data>>;
@@ -137,19 +140,21 @@ export type ValidatorInputError =
137140
| ValidatorInputMethodNotFoundError
138141
| ValidatorInputPathNotFoundError;
139142

140-
export const newValidatorMethodNotFoundError = (method: string) => ({
141-
target: "method" as const,
142-
actual: method,
143-
message: `method does not exist in endpoint` as const,
144-
});
143+
export const newValidatorMethodNotFoundError = (method: string) =>
144+
({
145+
target: "method" as const,
146+
actual: method,
147+
message: `method does not exist in endpoint` as const,
148+
}) satisfies StandardSchemaV1.Issue & Record<string, unknown>;
145149
type ValidatorInputMethodNotFoundError = ReturnType<
146150
typeof newValidatorMethodNotFoundError
147151
>;
148-
export const newValidatorPathNotFoundError = (path: string) => ({
149-
target: "path" as const,
150-
actual: path,
151-
message: `path does not exist in endpoints` as const,
152-
});
152+
export const newValidatorPathNotFoundError = (path: string) =>
153+
({
154+
target: "path" as const,
155+
actual: path,
156+
message: `path does not exist in endpoints` as const,
157+
}) satisfies StandardSchemaV1.Issue & Record<string, unknown>;
153158
type ValidatorInputPathNotFoundError = ReturnType<
154159
typeof newValidatorPathNotFoundError
155160
>;
@@ -179,7 +184,7 @@ export const newValidator = <E extends ApiEndpointsSchema>(endpoints: E) => {
179184
return Result.data(validators as ToValidators<E, Path, M>);
180185
};
181186
const res = <Path extends string, M extends string, SC extends number>(
182-
input: ResponseSpecValidatorGeneratorRawInput<Path, M, SC>,
187+
input: ResponseSpecValidatorGeneratorInput<Path, M, SC>,
183188
): Result<
184189
ToSSResponseValidators<ApiResponses<E, Path, M>, SC>,
185190
ValidatorInputError

pkgs/typed-api-spec/src/express/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,19 @@ export const validatorMiddleware = <const E extends ApiEndpointsSchema>(
110110
return {
111111
query: () =>
112112
({
113-
issues: [{ message: "", ...error }],
113+
issues: [error],
114114
}) satisfies StandardSchemaV1.FailureResult,
115115
params: () =>
116116
({
117-
issues: [{ message: "", ...error }],
117+
issues: [error],
118118
}) satisfies StandardSchemaV1.FailureResult,
119119
body: () =>
120120
({
121-
issues: [{ message: "", ...error }],
121+
issues: [error],
122122
}) satisfies StandardSchemaV1.FailureResult,
123123
headers: () =>
124124
({
125-
issues: [{ message: "", ...error }],
125+
issues: [error],
126126
}) satisfies StandardSchemaV1.FailureResult,
127127
};
128128
}

pkgs/typed-api-spec/src/fetch/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ type FetchT<UrlPrefix extends UrlPrefixPattern, E extends ApiEndpoints> = <
170170
export default FetchT;
171171

172172
export * from "./validation";
173+
export * from "./new-fetch";

0 commit comments

Comments
 (0)