Server → external: dedicated client module per vendor
**Scope: server → external vendor** (server-to-external). Your backend calling Stripe, SendGrid, or other third-party APIs — not browser-to-server calls to your API, not server-to-internal calls between your domains. External service calls go through one client module per vendor — not scattered `fetch` or SDK usage across features.
integrations-third-party-dedicated-client-module
Why it matters
| Stake | If ignored |
|---|---|
| Hidden coupling |
|
| Secret exposure |
|
| Hard to test |
|
How to fix
One server-side client library or module per external vendor. It owns auth, base URL, retries, and maps raw responses to your schemas. Backend feature code imports only that client — not the browser data-access client, not another domain's NestJS service.
Examples
ts
// server-side service — calling an external vendor, not your frontend API
async createCharge(amount: number) {
const res = await fetch('https://api.vendor.example/v1/charges', {
headers: { Authorization: `Bearer ${process.env.VENDOR_KEY}` },
body: JSON.stringify({ amount }),
});
return res.json();
}ts
export class VendorClient {
createCharge(input: CreateChargeInput): Promise<Charge> {
return this.http.post('/v1/charges', input).then((raw) => ChargeSchema.parse(raw));
}
}
await vendorClient.createCharge({ amount });