API Reference
Documentation complète de l'API de Company Manager.
API Reference
Documentation complète de l'API REST et tRPC de Company Manager.
API REST
Authentication
// POST /api/auth/login
interface LoginRequest {
email: string;
password: string;
}
interface LoginResponse {
token: string;
user: {
id: string;
email: string;
role: string;
};
}
// POST /api/auth/refresh
interface RefreshRequest {
refreshToken: string;
}
interface RefreshResponse {
token: string;
refreshToken: string;
}Users
// GET /api/users
interface GetUsersQuery {
page?: number;
limit?: number;
search?: string;
role?: string;
}
interface GetUsersResponse {
data: User[];
total: number;
page: number;
pageSize: number;
}
// POST /api/users
interface CreateUserRequest {
email: string;
name: string;
role: string;
tenantId: string;
}
// PUT /api/users/:id
interface UpdateUserRequest {
name?: string;
role?: string;
status?: 'active' | 'inactive';
}Orders
// GET /api/orders
interface GetOrdersQuery {
page?: number;
limit?: number;
status?: OrderStatus;
customerId?: string;
startDate?: string;
endDate?: string;
}
interface GetOrdersResponse {
data: Order[];
total: number;
page: number;
pageSize: number;
}
// POST /api/orders
interface CreateOrderRequest {
customerId: string;
items: {
productId: string;
quantity: number;
price: number;
}[];
shipping: {
address: string;
method: string;
};
billing: {
address: string;
method: string;
};
}
// PUT /api/orders/:id
interface UpdateOrderRequest {
status?: OrderStatus;
shipping?: Partial<ShippingInfo>;
billing?: Partial<BillingInfo>;
}API tRPC
Configuration
// server/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
import { Context } from './context';
const t = initTRPC.context<Context>().create({
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError:
error.code === 'BAD_REQUEST' &&
error.cause instanceof ZodError
? error.cause.flatten()
: null,
},
};
},
});
export const router = t.router;
export const publicProcedure = t.procedure;
export const protectedProcedure = t.procedure.use(isAuthed);Routers
Users Router
// server/routers/users.ts
export const usersRouter = router({
list: protectedProcedure
.input(
z.object({
page: z.number().optional(),
limit: z.number().optional(),
search: z.string().optional(),
})
)
.query(async ({ ctx, input }) => {
const users = await ctx.prisma.user.findMany({
where: {
tenantId: ctx.tenant.id,
OR: input.search
? [
{ name: { contains: input.search } },
{ email: { contains: input.search } },
]
: undefined,
},
take: input.limit,
skip: input.page * input.limit,
});
return users;
}),
create: protectedProcedure
.input(createUserSchema)
.mutation(async ({ ctx, input }) => {
return ctx.prisma.user.create({
data: {
...input,
tenantId: ctx.tenant.id,
},
});
}),
});Orders Router
// server/routers/orders.ts
export const ordersRouter = router({
list: protectedProcedure
.input(
z.object({
page: z.number().optional(),
limit: z.number().optional(),
status: z.enum(['draft', 'pending', 'completed']).optional(),
})
)
.query(async ({ ctx, input }) => {
const orders = await ctx.prisma.order.findMany({
where: {
tenantId: ctx.tenant.id,
status: input.status,
},
include: {
customer: true,
items: true,
},
take: input.limit,
skip: input.page * input.limit,
});
return orders;
}),
create: protectedProcedure
.input(createOrderSchema)
.mutation(async ({ ctx, input }) => {
return ctx.prisma.order.create({
data: {
...input,
tenantId: ctx.tenant.id,
status: 'draft',
},
});
}),
});Middleware
Authentication
// server/middleware/auth.ts
const isAuthed = t.middleware(async ({ ctx, next }) => {
if (!ctx.user) {
throw new TRPCError({
code: 'UNAUTHORIZED',
message: 'Not authenticated',
});
}
return next({
ctx: {
user: ctx.user,
},
});
});Tenant
// server/middleware/tenant.ts
const withTenant = t.middleware(async ({ ctx, next }) => {
const tenantId = ctx.headers['x-tenant-id'];
if (!tenantId) {
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'Tenant ID required',
});
}
const tenant = await ctx.prisma.tenant.findUnique({
where: { id: tenantId },
});
if (!tenant) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Tenant not found',
});
}
return next({
ctx: {
...ctx,
tenant,
},
});
});Utilisation Client
Configuration
// utils/trpc.ts
import { createTRPCNext } from '@trpc/next';
import { httpBatchLink, loggerLink } from '@trpc/client';
import type { AppRouter } from '../server/routers/_app';
export const trpc = createTRPCNext<AppRouter>({
config() {
return {
links: [
loggerLink(),
httpBatchLink({
url: '/api/trpc',
headers() {
return {
'x-tenant-id': getTenantId(),
};
},
}),
],
};
},
ssr: false,
});Hooks
// Exemple d'utilisation
const UserList = () => {
const { data, isLoading } = trpc.users.list.useQuery({
page: 0,
limit: 10,
});
const { mutate: createUser } = trpc.users.create.useMutation({
onSuccess: () => {
// Invalidation du cache
utils.users.list.invalidate();
},
});
return (
<div>
{data?.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
};Bonnes Pratiques
Sécurité
- Validation des entrées avec Zod
- Authentification et autorisation systématiques
- Rate limiting et protection CSRF
- Sanitization des données
Performance
- Pagination et filtrage côté serveur
- Mise en cache appropriée
- Optimisation des requêtes N+1
- Batch requests avec tRPC
Maintenance
- Versioning de l'API
- Documentation OpenAPI/Swagger
- Tests d'intégration
- Monitoring des erreurs