Skip to content

Commit

Permalink
Support Superstruct (#3)
Browse files Browse the repository at this point in the history
* feat: add superstruct support

* docs: change body validation
  • Loading branch information
Toshimichi0915 committed Jun 18, 2023
1 parent 64c8975 commit 2ec3d0a
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export default middleware<NextApiRequest, NextApiResponse>()

## Body Validation

This adapter validates the request body with zod or yup.
This adapter validates the request body with zod, yup, superstruct or custom validators.

```typescript
export function withValidatedBody<TReq extends { body?: unknown }, TRes extends ServerResponse, T>(parser: Parser<T>)
Expand Down
16 changes: 16 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"prettier": "^2.8.8",
"rimraf": "^5.0.0",
"semantic-release": "^21.0.2",
"superstruct": "^1.0.3",
"typescript": "^5.0.4",
"vitest": "^0.31.0",
"yup": "^1.1.1",
Expand Down
11 changes: 10 additions & 1 deletion src/adapters/validation-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ interface YupLike<T> {
cast: (value: unknown) => T
}

/**
* Parse the body of a request using Superstruct.
*/
interface SuperstructLike<T> {
create: (value: unknown) => T
}

/**
* Parse the body of a request using a function.
*/
Expand All @@ -23,7 +30,7 @@ type FunctionalParser<T> = (value: unknown) => T
/**
* A parser that can be used to parse the body of a request.
*/
type Parser<T> = ZodLike<T> | YupLike<T> | FunctionalParser<T>
type Parser<T> = ZodLike<T> | YupLike<T> | SuperstructLike<T> | FunctionalParser<T>

/**
* Convert a parser to a functional parser.
Expand All @@ -35,6 +42,8 @@ function uniformParser<T>(parser: Parser<T>): FunctionalParser<T> {
return (value: unknown) => parser.parse(value)
} else if ("cast" in parser) {
return (value: unknown) => parser.cast(value)
} else if ("create" in parser) {
return (value: unknown) => parser.create(value)
} else if (typeof parser === "function") {
return parser
}
Expand Down
42 changes: 42 additions & 0 deletions test/adapters/validation-adapter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, it, vitest } from "vitest"
import { z } from "zod"
import yup from "yup"
import superstruct from "superstruct"
import { middleware, withValidatedBody } from "../../src"
import { ServerResponse } from "http"

Expand Down Expand Up @@ -47,6 +48,27 @@ describe("withValidatedBody", () => {
})
})

it("superstruct", async ({ expect }) => {
const res = {
setHeader: vitest.fn(),
end: vitest.fn(),
}

const superstructSchema = superstruct.object({
name: superstruct.string(),
})

const f = middleware<{ body: unknown }, ServerResponse>()
.pipe(withValidatedBody(superstructSchema))
.pipe((req, res, next, body) => body)

const result = await f({ body: { name: "abc" } }, res as never)

expect(result).toEqual({
name: "abc",
})
})

it("zod invalid", async ({ expect }) => {
const res = {
setHeader: vitest.fn(),
Expand Down Expand Up @@ -87,6 +109,26 @@ describe("withValidatedBody", () => {
expect(res.statusCode).toEqual(400)
})

it("superstruct invalid", async ({ expect }) => {
const res = {
setHeader: vitest.fn(),
statusCode: 0,
end: vitest.fn(),
}

const schema = superstruct.object({
name: superstruct.string(),
})

const f = middleware<{ body: unknown }, ServerResponse>()
.pipe(withValidatedBody(schema))
.pipe((req, res, next, body) => body)

await f({ body: { age: "heheheha" } }, res as never)

expect(res.statusCode).toEqual(400)
})

it("custom", async ({ expect }) => {
const res = {
setHeader: vitest.fn(),
Expand Down

0 comments on commit 2ec3d0a

Please sign in to comment.