next-better-api
Advanced tools
Comparing version 0.1.3 to 0.1.4
@@ -54,4 +54,3 @@ "use strict"; | ||
const validateEndpointSchemaForRequest = (endpointDef, req) => { | ||
const querySchema = endpointDef.querySchema; | ||
const bodySchema = endpointDef.bodySchema; | ||
const { querySchema, bodySchema } = endpointDef; | ||
const errorResponse = ({ errors }) => JSON.stringify({ | ||
@@ -61,11 +60,11 @@ errors, | ||
if (querySchema) { | ||
const schemaParse = querySchema === null || querySchema === void 0 ? void 0 : querySchema.safeParse(req.query); | ||
if (!(schemaParse === null || schemaParse === void 0 ? void 0 : schemaParse.success)) { | ||
return errorResponse(schemaParse.error); | ||
const querySchemaParse = querySchema === null || querySchema === void 0 ? void 0 : querySchema.safeParse(req.query); | ||
if (!(querySchemaParse === null || querySchemaParse === void 0 ? void 0 : querySchemaParse.success)) { | ||
return errorResponse(querySchemaParse.error); | ||
} | ||
} | ||
if (bodySchema) { | ||
const schemaParse = bodySchema === null || bodySchema === void 0 ? void 0 : bodySchema.safeParse(req.body); | ||
if (!(schemaParse === null || schemaParse === void 0 ? void 0 : schemaParse.success)) { | ||
return errorResponse(schemaParse.error); | ||
const bodySchemaParse = bodySchema === null || bodySchema === void 0 ? void 0 : bodySchema.safeParse(req.body); | ||
if (!(bodySchemaParse === null || bodySchemaParse === void 0 ? void 0 : bodySchemaParse.success)) { | ||
return errorResponse(bodySchemaParse.error); | ||
} | ||
@@ -108,2 +107,11 @@ } | ||
const { status, redirect, body, headers } = yield handler(Object.assign(Object.assign(Object.assign({}, routeContext), endpointContext), { query: req.query, body: req.body })); | ||
if (body && endpointDef.responseSchema) { | ||
const responseSchemaParse = endpointDef.responseSchema.safeParse(body); | ||
// TODO: Handle response schema errors differently: | ||
// - Allow configuring throw rule through options | ||
// - Default to throwing in development only, warning otherwise | ||
if (!responseSchemaParse.success) { | ||
throw responseSchemaParse.error; | ||
} | ||
} | ||
setResponseHeaders(res, headers); | ||
@@ -110,0 +118,0 @@ if (redirect) { |
{ | ||
"name": "next-better-api", | ||
"version": "0.1.3", | ||
"version": "0.1.4", | ||
"description": "Utilities for safer, easier APIs with NextJS", | ||
@@ -23,3 +23,3 @@ "keywords": [ | ||
"dev": "ts-node src/index.ts", | ||
"prepack": "yarn lint && yarn build" | ||
"prepack": "prettier -c . && yarn lint && yarn test && yarn build" | ||
}, | ||
@@ -26,0 +26,0 @@ "peerDependencies": { |
# next-better-api ⚡️🔵 [![npm version](https://badge.fury.io/js/next-better-api.svg)](https://badge.fury.io/js/next-better-api) | ||
Opinionated helpers for building better [NextJS](https://nextjs.org/) APIs, powered by [Zod](https://github.com/colinhacks/zod). | ||
Opinionated TypeScript-first helpers for building better [NextJS](https://nextjs.org/) APIs, powered by [Zod](https://github.com/colinhacks/zod). | ||
<p align="center"> | ||
<img src="./logo.svg"> | ||
<img src="./logo.svg"> | ||
</p> | ||
## At a glance: | ||
- 🙅♀️ Hands-off Typescript type inference based on your Zod validation schemas for `req.query`, `req.body` and your API response | ||
- ✨ Type inference helpers to use with `react-query`, `fetch`, and other client-side utilities | ||
- 🔌 Minimal and composable — bring your own request context, add middleware, etc | ||
```ts | ||
@@ -13,18 +19,19 @@ import { z } from 'zod'; | ||
const getUsers = endpoint( | ||
const getUser = endpoint( | ||
{ | ||
method: 'get', | ||
querySchema: z.object({ | ||
id: z.string(), | ||
}), | ||
responseSchema: z.object({ | ||
users: z.array( | ||
z.object({ | ||
id: z.string(), | ||
name: z.string(), | ||
email: z.string(), | ||
active: z.boolean(), | ||
}) | ||
), | ||
user: z.object({ | ||
id: z.string(), | ||
name: z.string(), | ||
email: z.string(), | ||
active: z.boolean(), | ||
}), | ||
}), | ||
}, | ||
async () => { | ||
const users = await getAllUsers(); | ||
async ({ req }) => { | ||
const user = await getUser(req.query.id); | ||
@@ -34,3 +41,3 @@ return { | ||
body: { | ||
users, | ||
user, | ||
}, | ||
@@ -41,3 +48,3 @@ }; | ||
export asHandler([getUsers]); | ||
export default asHandler([getUser]); | ||
``` | ||
@@ -44,0 +51,0 @@ |
@@ -8,3 +8,3 @@ { | ||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ | ||
"composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ | ||
"composite": true /* Enable constraints that allow a TypeScript project to be used with project references. */, | ||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ | ||
@@ -16,3 +16,3 @@ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ | ||
/* Language and Environment */ | ||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ | ||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, | ||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ | ||
@@ -31,3 +31,3 @@ // "jsx": "preserve", /* Specify what JSX code is generated. */ | ||
/* Modules */ | ||
"module": "commonjs", /* Specify what module code is generated. */ | ||
"module": "commonjs" /* Specify what module code is generated. */, | ||
// "rootDir": "./", /* Specify the root folder within your source files. */ | ||
@@ -56,3 +56,3 @@ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ | ||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ | ||
"outDir": "./build", /* Specify an output folder for all emitted files. */ | ||
"outDir": "./build" /* Specify an output folder for all emitted files. */, | ||
// "removeComments": true, /* Disable emitting comments. */ | ||
@@ -79,8 +79,8 @@ // "noEmit": true, /* Disable emitting files from a compilation. */ | ||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ | ||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ | ||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, | ||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ | ||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ | ||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, | ||
/* Type Checking */ | ||
"strict": true, /* Enable all strict type-checking options. */ | ||
"strict": true /* Enable all strict type-checking options. */, | ||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ | ||
@@ -107,4 +107,4 @@ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ | ||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ | ||
"skipLibCheck": true /* Skip type checking all .d.ts files. */ | ||
"skipLibCheck": true /* Skip type checking all .d.ts files. */ | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
84628
17
373
186