Repository navigation
Where should ts-rest contract and client live in a custom-layered FSD project? #920
ContextI'm using FSD with a custom layer stack in a Next.js App Router project that also uses ts-rest for end-to-end type-safe API contracts. My current layer order (top to bottom) is: The problemI have three related issues that create a circular dependency: 1. Contract references schemas from multiple layers The ts-rest contract ( // api/contract.ts
import { PostSchema } from 'entities/post' // ✅ downward, fine
import { SomeSchema } from 'pages/some-page' // ❌ upward violation2. The fetch client is used by lower layers The ts-rest fetch client ( // features/post/api/use-posts.query.ts
import { client } from 'api/client' // ❌ upward import from features → api3. The contract is a shared resource that doesn't fit cleanly into any layer The contract is simultaneously:
This makes it impossible to place the contract in a single layer without either violating import direction rules or forcing all schemas into an inconvenient location. What I've consideredOption A: Move contract + client to This aligns with the official docs (v2.1 release notes mention that "API calls are now explicitly allowed in Shared"). The contract would import zod schemas from But this requires moving domain-specific zod schemas into Option B: Move the entire Reorder the layer stack so This makes Option C: Treat Place the contract in a top-level QuestionWhat is the recommended FSD approach for placing a shared API contract (like ts-rest or tRPC router) that:
Is Option A (contract in Any guidance from the core team would be very appreciated! |
Replies: 1 comment
|
Hey Option A is indeed the preferred way of handling API requests (as per documentation). The issue you are getting with zod schemas is related to the fact that CRUD operation code is leaking outside
This is, in fact, not true. The frontend application has no control over the type or validation rules for the schema. This schema and its respective types describe the payload types, not domain logic. This follows the same pattern of DDD and clean architecture, where controller/adapter validations and domain logic are separated. So I would suggest you move schemas and validations to I don't know details of your project, but there are 2 options for server-client typesafety: you can either create a private package in your monorepo that exposes those types (and schemas) to both client and server, or you can follow a pattern of having suffixed public API files like |
Hey
Option A is indeed the preferred way of handling API requests (as per documentation). The issue you are getting with zod schemas is related to the fact that CRUD operation code is leaking outside
shared/apiintoentitieslayer https://fsd.how/docs/guides/issues/excessive-entities/#3-exclude-crud-operations-from-entitiesThis is, in fact, not true. The frontend application has no control over the type or validation rules for the schema. This schema and its respective types describe the payload types, not domain logic. This follows the same pattern of DD…