Overview
@empathyco/x-adapter is a utility library for creating type-safe API clients. It provides tools to connect with any API endpoint, transform requests into API-compatible formats, make HTTP requests, and transform responses back into desired shapes.
Installation
npm install @empathyco/x-adapter
Main Exports
Endpoint Adapter
Core functionality for creating API adapters.
Factory function to create endpoint adapters with custom options
Interface for adapters that connect with API endpoints
ExtendableEndpointAdapter
Endpoint adapter with extend functionality for composition
HTTP Clients
HTTP client implementations for making requests.
HTTP client using the native Fetch API
Interface for HTTP client implementations
Mappers
Utilities for transforming requests and responses.
Pass-through mapper that returns the input unchanged
Interface for mapper functions that transform data
Schemas
Schema validation utilities.
Validates data against defined schemas
Creating an Adapter
Basic Example
import { endpointAdapterFactory } from '@empathyco/x-adapter'
interface SearchRequest {
query : string
rows : number
}
interface SearchResponse {
results : Array <{ id : string ; title : string }>
totalResults : number
}
const searchAdapter = endpointAdapterFactory < SearchRequest , SearchResponse >({
endpoint: 'https://api.example.com/search' ,
requestMapper : ( request ) => ({
q: request . query ,
size: request . rows
}),
responseMapper : ( response ) => ({
results: response . items ,
totalResults: response . total
})
})
// Use the adapter
const response = await searchAdapter ({
query: 'shoes' ,
rows: 20
})
Endpoint Adapter Options
endpoint
string | Mapper<Request, string>
The API endpoint URL. Can be a static string or a function that generates the URL from the request
The HTTP client to use for requests. Defaults to fetchHttpClient
Default options applied to every request (headers, method, etc.)
requestMapper
Mapper<Request, Record<string, any>>
Function to transform the request object before sending to the API
Function to transform the API response into the desired format
Advanced Usage
Dynamic Endpoints
const productAdapter = endpointAdapterFactory ({
endpoint : ( request ) => `https://api.example.com/products/ ${ request . productId } ` ,
responseMapper : ( response ) => ({
... response ,
price: parseFloat ( response . price )
})
})
Extending Adapters
const baseAdapter = endpointAdapterFactory ({
endpoint: 'https://api.example.com' ,
defaultRequestOptions: {
headers: {
'Content-Type' : 'application/json'
}
}
})
// Extend with authentication
const authenticatedAdapter = baseAdapter . extends ({
defaultRequestOptions: {
headers: {
'Authorization' : 'Bearer token123'
}
}
})
Custom Request Mapper
const searchAdapter = endpointAdapterFactory ({
endpoint: '/api/search' ,
requestMapper : ( request ) => {
const params : Record < string , any > = {
q: request . query
}
if ( request . filters ) {
params . filters = request . filters . map ( f => f . id ). join ( ',' )
}
if ( request . sort ) {
params . sort = request . sort
}
return params
}
})
const facetsAdapter = endpointAdapterFactory ({
endpoint: '/api/facets' ,
responseMapper : ( response ) => ({
facets: response . facets . map ( facet => ({
id: facet . facet_id ,
label: facet . facet_name ,
filters: facet . values . map ( value => ({
id: value . value_id ,
label: value . value_name ,
totalResults: value . count ,
selected: false
}))
}))
})
})
Type Definitions
EndpointAdapter
interface EndpointAdapter < Request , Response > {
( request : Request , options ?: RequestOptions ) : Promise < Response >
}
ExtendableEndpointAdapter
interface ExtendableEndpointAdapter < Request , Response >
extends EndpointAdapter < Request , Response > {
extends : < NewRequest = Request , NewResponse = Response >(
options : Partial < EndpointAdapterOptions < NewRequest , NewResponse >>
) => ExtendableEndpointAdapter < NewRequest , NewResponse >
}
Mapper
type Mapper < Input , Output > = (
input : Input ,
context ?: Record < string , any >
) => Output
RequestOptions
interface RequestOptions {
endpoint ?: string
method ?: 'GET' | 'POST' | 'PUT' | 'DELETE'
headers ?: Record < string , string >
parameters ?: Record < string , any >
}
Error Handling
try {
const response = await searchAdapter ({
query: 'shoes' ,
rows: 20
})
} catch ( error ) {
if ( error . message === 'Tried to make a request without an endpoint' ) {
// Handle missing endpoint
}
// Handle other errors
}
Dependencies
The package depends on:
@empathyco/x-deep-merge - Deep merging utilities
@empathyco/x-utils - General utility functions
Resources
GitHub Repository View source code
x-components See how adapters integrate with components