Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/typed-api-spec.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions src/common/validate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, it, expect } from "vitest";
import { getApiSpec } from "./validate";
import { AnyApiEndpoints } from "./spec";
describe("getApiSpec", () => {
const spec: AnyApiEndpoints = {
"/users": {
get: {
responses: { 200: { description: "ok" } },
},
},
};
it("should return path and method if valid path and method provided", () => {
const { data, error } = getApiSpec(spec, "/users", "get");
expect(data).toEqual({ responses: { 200: { description: "ok" } } });
expect(error).toBeUndefined();
});
it("should return error if invalid path provided", () => {
const { data, error } = getApiSpec(spec, "", "get");
expect(data).toBeUndefined();
expect(error).toEqual({
actual: "",
message: "path does not exist in endpoints",
});
});
it("should return error if no exist method provided", () => {
const { data, error } = getApiSpec(spec, "/users", "post");
expect(data).toBeUndefined();
expect(error).toEqual({
actual: "post",
message: "method does not exist in endpoint",
target: "method",
});
});
});
15 changes: 4 additions & 11 deletions src/common/validate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Result } from "../utils";
import { AnyApiEndpoint, AnyApiEndpoints, isMethod, Method } from "./spec";
import { AnyApiEndpoint, AnyApiEndpoints, Method } from "./spec";
import { ParsedQs } from "qs";

export type Validators<
Expand Down Expand Up @@ -57,15 +57,8 @@ const validatePath = <E extends AnyApiEndpoints, Path extends string>(

const validateMethod = <Endpoint extends AnyApiEndpoint, M extends string>(
endpoint: Endpoint,
method: M,
method: M & Method,
): Result<keyof Endpoint & M, ValidationError> => {
if (!isMethod(method)) {
return Result.error({
target: "method",
actual: method,
message: `invalid method`,
});
}
if (endpoint[method] === undefined) {
return Result.error({
target: "method",
Expand All @@ -79,7 +72,7 @@ const validateMethod = <Endpoint extends AnyApiEndpoint, M extends string>(
const validatePathAndMethod = <
E extends AnyApiEndpoints,
Path extends string,
M extends string,
M extends string & Method,
>(
endpoints: E,
maybePath: Path,
Expand All @@ -98,7 +91,7 @@ const validatePathAndMethod = <
export const getApiSpec = <
E extends AnyApiEndpoints,
Path extends string,
M extends string,
M extends string & Method,
>(
endpoints: E,
maybePath: Path,
Expand Down
13 changes: 8 additions & 5 deletions src/valibot/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
BaseApiSpec,
DefineApiResponses,
DefineResponse,
isMethod,
Method,
StatusCode,
} from "../common";
Expand Down Expand Up @@ -93,11 +94,13 @@ export const newValibotValidator = <E extends ValibotApiEndpoints>(
return <Path extends keyof E & string, M extends keyof E[Path] & Method>(
input: ValidatorsInput,
) => {
const { data: spec, error } = getApiSpec(
endpoints,
input.path,
input.method?.toLowerCase(),
);
const method = input.method?.toLowerCase();
if (!isMethod(method)) {
return {} as E[Path][M] extends ValibotApiSpec
? ValibotValidators<E[Path][M], "">
: Record<string, never>;
}
const { data: spec, error } = getApiSpec(endpoints, input.path, method);
if (error !== undefined) {
return {} as E[Path][M] extends ValibotApiSpec
? ValibotValidators<E[Path][M], "">
Expand Down
13 changes: 8 additions & 5 deletions src/zod/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
BaseApiSpec,
DefineApiResponses,
DefineResponse,
isMethod,
Method,
StatusCode,
} from "../common";
Expand Down Expand Up @@ -89,11 +90,13 @@ export const newZodValidator = <E extends ZodApiEndpoints>(endpoints: E) => {
return <Path extends keyof E & string, M extends keyof E[Path] & Method>(
input: ValidatorsInput,
) => {
const { data: spec, error } = getApiSpec(
endpoints,
input.path,
input.method?.toLowerCase(),
);
const method = input.method?.toLowerCase();
if (!isMethod(method)) {
return {} as E[Path][M] extends ZodApiSpec
? ZodValidators<E[Path][M], "">
: Record<string, never>;
}
const { data: spec, error } = getApiSpec(endpoints, input.path, method);
if (error !== undefined) {
return {} as E[Path][M] extends ZodApiSpec
? ZodValidators<E[Path][M], "">
Expand Down