REST Overrides
Naming conventions handle most routes, but some endpoints need custom paths or HTTP methods — login flows, webhook receivers, or legacy URL patterns. The .rest() method lets you override the generated path, method, or status code for any individual procedure.
Basic Override
Section titled “Basic Override”loginUser: procedure() .input(z.object({ email: z.string(), password: z.string() })) .mutation(handler) .rest({ method: 'POST', path: '/auth/login', }),Override Options
Section titled “Override Options”method
Section titled “method”Force a specific HTTP method:
.rest({ method: 'POST' }) // POST instead of inferred.rest({ method: 'GET' }) // GET instead of inferredCustom path (overrides resource-based path):
// Without override: POST /api/users// With override: POST /auth/register.rest({ path: '/auth/register' })Path Parameters
Section titled “Path Parameters”Include params in the path:
verifyEmail: procedure() .input(z.object({ token: z.string() })) .mutation(handler) .rest({ method: 'GET', path: '/verify/:token', }),// GET /api/verify/abc123tRPC-Only Procedures
Section titled “tRPC-Only Procedures”Procedures that don’t match a naming convention prefix and have no .rest() override are automatically tRPC-only — no REST endpoint is generated:
// No recognized prefix → tRPC-only, no REST routesyncExternalData: procedure() .query(handler),Common Patterns
Section titled “Common Patterns”Auth Endpoints
Section titled “Auth Endpoints”procedures('auth', { register: procedure() .input(RegisterSchema) .mutation(handler) .rest({ method: 'POST', path: '/auth/register' }),
login: procedure() .input(LoginSchema) .mutation(handler) .rest({ method: 'POST', path: '/auth/login' }),
logout: procedure() .mutation(handler) .rest({ method: 'POST', path: '/auth/logout' }),
refreshToken: procedure() .input(z.object({ refreshToken: z.string() })) .mutation(handler) .rest({ method: 'POST', path: '/auth/refresh' }),});Nested Resources
Section titled “Nested Resources”For nested resources, use the .parent() or .parents() methods instead of manual .rest() overrides. See Nested Routes for details.
// RECOMMENDED: Use .parent() for automatic nestingprocedures('comments', { listComments: procedure() .parent('posts') .input(z.object({ postId: z.string() })) .query(handler), // → GET /posts/:postId/comments});
// ALTERNATIVE: Manual override (less maintainable)procedures('comments', { listPostComments: procedure() .input(z.object({ postId: z.string() })) .query(handler) .rest({ method: 'GET', path: '/posts/:postId/comments', }),});Bulk Operations
Section titled “Bulk Operations”procedures('users', { bulkCreate: procedure() .input(z.object({ users: z.array(CreateUserSchema) })) .mutation(handler) .rest({ method: 'POST', path: '/users/bulk', }),
bulkDelete: procedure() .input(z.object({ ids: z.array(z.string()) })) .mutation(handler) .rest({ method: 'DELETE', path: '/users/bulk', }),});Action Endpoints
Section titled “Action Endpoints”procedures('orders', { cancelOrder: procedure() .input(z.object({ id: z.string() })) .mutation(handler) .rest({ method: 'POST', path: '/orders/:id/cancel', }),
shipOrder: procedure() .input(z.object({ id: z.string(), trackingNumber: z.string() })) .mutation(handler) .rest({ method: 'POST', path: '/orders/:id/ship', }),});Path Parameter Extraction
Section titled “Path Parameter Extraction”Path params are automatically merged into input:
getOrderItem: procedure() .input(z.object({ orderId: z.string(), itemId: z.string(), })) .query(({ input }) => { // input.orderId and input.itemId available }) .rest({ method: 'GET', path: '/orders/:orderId/items/:itemId', }),Client-Side Route Config
Section titled “Client-Side Route Config”When using @veloxts/client in REST mode, procedures with .rest() overrides need matching route entries in the client config. See Client Package — Custom Routes for details.
Related Content
Section titled “Related Content”- REST Conventions - Default patterns
- Client Package - Frontend route resolution
- Nested Routes - Hierarchical resources
- OpenAPI - API documentation