
Security News
Cline CLI npm Package Compromised via Suspected Cache Poisoning Attack
A compromised npm publish token was used to push a malicious postinstall script in cline@2.3.0, affecting the popular AI coding agent CLI with 90k weekly downloads.
@appgeist/restful-next-api
Advanced tools
Build restful API methods for Next.js > 9 and validate the incoming requests with yup

Build restful API methods for Next.js > 9 and validate the incoming requests with yup.
Next.js brought API routes support in v9, but you have to provide your own implementation of handling different rest methods (GET, POST, PUT, PATCH, DELETE). This helper enables you to clearly structure your method handling and validation.
npm i @appgeist/restful-next-api or yarn add @appgeist/restful-next-api;npx install-peerdeps -do @appgeist/restful-next-api to make sure you have the necessary peerDependencies (yup and of course next) in your project.In /pages/api/products.js:
import { object, number, string } from 'yup';
import methods from '@appgeist/restful-next-api';
import { Product, User } from '~/models';
import { log } from '~/utils';
export default methods({
get: ({ query: { page } }) => Product.browse({ page }),
post: {
bodySchema: object({
name: string()
.min(5)
.max(20)
.required(),
description: string()
.min(5)
.max(1000),
price: number()
.positive()
.max(9999)
.required(),
inventoryItems: number()
.integer()
.positive()
.max(999)
.required()
}).noUnknown(),
onRequest: async ({ body, req }) => {
const product = await Product.create(body);
await log(`Product ${product.id} created at ${new Date()} by user ${req.userId}`);
return product;
}
}
});
In /pages/api/products/[id].js:
import { object, number, string } from 'yup';
import { FORBIDDEN } from 'http-status-codes';
import methods, { ApiError } from '@appgeist/restful-next-api';
import { Product } from '~/models';
import { log } from '~/utilities';
export default methods({
patch: {
querySchema: {
id: number()
.integer()
.positive()
.required()
},
bodySchema: object({
name: string()
.min(5)
.max(20)
.required(),
description: string()
.min(5)
.max(1000),
price: number()
.positive()
.max(9999)
.required(),
inventoryItems: number()
.integer()
.positive()
.max(999)
.required()
}).noUnknown(),
onRequest: async ({ body, req }) => {
const product = await Product.create(body);
await log(`Product ${product.id} updated at ${new Date()} by user ${req.userId}`);
return product;
}
},
delete: {
querySchema: {
id: number()
.integer()
.positive()
.required()
},
onRequest: async ({ query: { id }, req }) => {
const { userId } = req;
const acl = await User.getACL(userId);
if (!acl.includes('deleteProduct')) throw new ApiError(FORBIDDEN);
await Product.destroy(id);
await log(`Product ${id} deleted at ${new Date()} by user ${userId}`);
}
}
});
Each method can be:
{ querySchema, bodySchema, handler, errorHandler }.A querySchema/bodySchema definition can be:
.noUnknown() modifier)For each request, the beforeRequest handler is invoked if present:
import methods from '@appgeist/restful-next-api';
export default methods({
get: {
beforeRequest: () => {
console.log('Before GET');
},
onRequest: () => {
console.log('On GET request');
}
},
delete: () => {
console.log('On DELETE request');
},
beforeRequest: () => {
// ...
console.log('Before REQUEST');
// ...
}
});
If beforeRequest completes without throwing an error, the data for each request is validated (and transformed) according to the specified querySchema and bodySchema definitions. See yup readme for more information on data validation and transformation.
400 (BAD_REQUEST) response is sent to the client with a JSON body type structured like so:{
"message": "There were 2 validation errors",
"errors": ["body.price must be an integer", "body.inventoryItems is required"]
}
onRequest handler will be invoked.The onRequest handler:
function onRequest({ query, body, req }) => { /* do work and return data */ };
...or
async function onRequest({ query, body, req }) => { /* do work and return Promise which resolves to data */ };
This method can return an object or a Promise resolving to an object that will be serialized to JSON and sent back to the client with a 200 (OK) status code. If onRequest returns undefined or null, an empty response will be sent with a 201 (CREATED) header for POST requests and 204 (NO_CONTENT) for non-POST request.
Default error handling
If beforeRequest or onRequest throws an ApiError (also exported by @appgeist/restful-next-api), a specific http status code is returned to the client. For instance, the following code will result in a 403 (FORBIDDEN) being sent to the client:
import methods, { ApiError } from '@appgeist/restful-next-api';
import { FORBIDDEN } from 'http-status-codes';
export default methods({
get: {
// ...
onRequest: () => {
// ...
throw new ApiError(FORBIDDEN);
// ...
}
// ...
}
});
Other error types are treated as 500 / INTERNAL_SERVER_ERROR and are also logged to the console.
You can override the default error handling mechanism by providing a custom error handling function like so:
export default methods({
patch: {
// querySchema: ..., bodySchema: ...,
onRequest: ({ body, req }) => {
/* handle patch request */
},
// Error handler for patch requests
onError: ({ res, err }) => {
res.status(500).send('Error while trying to patch');
}
},
delete: {
// querySchema: ...,
onRequest: ({ query: { id }, req }) => {
/* handle delete request */
}
},
// Generic error handler - this will also handle errors for delete requests
onError: ({ res, err }) => {
res.status(500).send('Error');
}
});
A specific method error handler takes precedence over the generic error handler.
JsDocs are provided for IDE support for now; an index.d.ts will be provided at some point in the future.
The ISC License.
FAQs
Build restful API methods for Next.js > 9 and validate the incoming requests with yup
The npm package @appgeist/restful-next-api receives a total of 62 weekly downloads. As such, @appgeist/restful-next-api popularity was classified as not popular.
We found that @appgeist/restful-next-api demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
A compromised npm publish token was used to push a malicious postinstall script in cline@2.3.0, affecting the popular AI coding agent CLI with 90k weekly downloads.

Product
Socket is now scanning AI agent skills across multiple languages and ecosystems, detecting malicious behavior before developers install, starting with skills.sh's 60,000+ skills.

Product
Socket now supports PHP with full Composer and Packagist integration, enabling developers to search packages, generate SBOMs, and protect their PHP dependencies from supply chain threats.