About external-api-adapters
A development skill for designing adapters around external APIs. It helps teams isolate vendor and network details while validating data, controlling retries, and normalizing errors.
Key features
- 01Ports-and-adapters boundaries
- 02DTO validation and conversion
- 03Normalized application errors
- 04Bounded, operation-safe retries
- 05Timeouts and structured evidence
- 06Adapter testing guidance
Use cases
- 01Integrating an external vendor API
- 02Preventing SDK details from spreading
- 03Handling transient network failures
- 04Testing malformed external responses
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ marcioaltoe/ skills --skill external-api-adaptersAfter installing, type/external-api-adaptersin Claude Code to confirm it loaded.
Details
From the project READMEExternal API Adapters
Use this skill when code crosses a process or vendor boundary.
Core Rules
- Keep external APIs behind adapters. Domain and use case code should depend on ports, not SDKs or HTTP client details.
- Convert external DTOs into internal domain/application types at the boundary.
- Normalize external errors into a small set of application errors.
- Set explicit timeouts for every network call.
- Make retry behavior deliberate, bounded, and safe for the operation.
- Capture correlation IDs, request IDs, vendor IDs, and pagination cursors as structured evidence.
- Keep credentials and raw sensitive payloads out of logs, snapshots, and thrown messages.
Adapter Shape
export interface ErpCustomerGateway {
fetchCustomer(id: CustomerId): Promise<ExternalCustomerResult>;
}
export class HttpErpCustomerAdapter implements ErpCustomerGateway {
async fetchCustomer(id: CustomerId): Promise<ExternalCustomerResult> {
// HTTP or SDK details stay here.
}
}
Prefer one adapter per external capability or bounded integration. Avoid large "vendor client" classes that mix unrelated operations.
Boundary Checklist
- Input is validated before leaving the application.
- Output is parsed and validated before entering the application.
- Timeouts are configured and tested.
- Retry policy is documented by operation.
- Non-idempotent calls have idempotency keys or no automatic retry.
- Pagination and cursors have deterministic stop conditions.
- Rate limit responses are handled explicitly.
- Logs include operation, external system, request ID, and safe identifiers.
- The adapter has tests for success, validation failure, timeout, retryable failure, non-retryable failure, and malformed response.
Retry Guidance
Retry only when the operation is idempotent or has an idempotency key. Do not retry validation failures, authentication failures, authorization failures, or permanent business-rule responses.
Use small bounded retries with jitter for transient network failures and 5xx responses. Surface repeated failure as a typed application error.
Error Normalization
Map vendor-specific details to application errors:
type ExternalServiceError =
| { kind: "unavailable"; retryAfterMs?: number; requestId?: string }
| { kind: "unauthorized"; requestId?: string }
| { kind: "not-found"; requestId?: string }
| { kind: "invalid-response"; requestId?: string; reason: string };
The rest of the application should not branch on SDK exception names or raw HTTP status codes unless the adapter contract explicitly exposes them.
Testing Guidance
- Unit test mapping and error normalization with focused fixtures.
- Use contract tests for real or recorded external response shapes.
- Keep fake clients behavior-based, not assertion-only mocks.
- Include negative fixtures for malformed, partial, and unexpected responses.
- Verify observability fields for failure paths when operations teams need them.
Common Mistakes
- Passing external DTOs through the application unchanged.
- Retrying non-idempotent operations.
- Hiding partial failure behind empty arrays or
undefined. - Treating all 4xx or all 5xx responses the same.
- Adding SDK imports throughout use case or domain code.