| title |
|---|
API action validator |
Validation in Ship is handled automatically by providing a schema to createEndpoint. When schema is present, the validate middleware auto-applies and merges body + files + query + params into ctx.validatedData.
For additional validation logic (e.g. checking uniqueness), add custom middleware functions to the middlewares array.
import { z } from 'zod';
import createEndpoint from 'routes/createEndpoint';
import isPublic from 'middlewares/isPublic';
const schema = z.object({
firstName: z.string().min(1, 'Please enter first name.').max(100),
lastName: z.string().min(1, 'Please enter last name.').max(100),
email: z.email('Email format is incorrect.'),
password: z.string().min(6, 'Password must be at least 6 characters'),
});
export default createEndpoint({
method: 'post',
path: '/sign-up',
schema,
middlewares: [isPublic],
async handler(ctx) {
const { firstName, lastName, email, password } = ctx.validatedData;
// ...action code
},
});To add extra validation logic beyond the Zod schema, add a custom middleware to the middlewares array:
import { z } from 'zod';
import createEndpoint from 'routes/createEndpoint';
import isPublic from 'middlewares/isPublic';
import { userService } from 'resources/user';
const schema = z.object({
email: z.email('Email format is incorrect.'),
password: z.string().min(6, 'Password must be at least 6 characters'),
});
const checkUserExists = async (ctx, next) => {
const { email } = ctx.validatedData;
const exists = await userService.exists({ email });
if (exists) {
ctx.throwClientError({ email: 'User with this email is already registered' });
return;
}
await next();
};
export default createEndpoint({
method: 'post',
path: '/sign-up',
schema,
middlewares: [isPublic, checkUserExists],
async handler(ctx) {
const { email, password } = ctx.validatedData;
// ...action code
},
});