@deliverart/sdk-js-core
v2.6.9
Published
Core SDK for DeliverArt, providing essential functionalities and utilities.
Downloads
12,726
Readme
@deliverart/sdk-js-core
Core package for the DeliverArt JavaScript SDK. Provides the API client, plugin system, and base request/response handling.
Installation
npm install @deliverart/sdk-js-core
# or
pnpm add @deliverart/sdk-js-core
# or
yarn add @deliverart/sdk-js-coreExported Types
ApiClient
type ApiClient<Extensions extends ApiExtension = NonNullable<unknown>>The main API client interface that provides methods to make API calls and manage plugins.
Methods:
call<TInputSchema, TOutputSchema, Q, H>(request: AbstractApiRequest): Promise<output<TOutputSchema>>- Execute an API requestaddPlugin<T extends ApiExtension>(plugin: ApiClientPlugin<T>): ApiClient<T>- Add a plugin to extend client functionalityaddRequestMiddleware(middleware: RequestMiddleware): void- Add middleware to intercept requestsaddResponseMiddleware(middleware: ResponseMiddleware): void- Add middleware to intercept responses
AbstractApiRequest
abstract class AbstractApiRequest<
TInputSchema extends ZodType<any, any, any>,
TOutputSchema extends ZodType<any, any, any>,
Query = unknown,
Headers = unknown
>Base class for all API requests. Extend this class to create custom API requests.
Abstract Properties:
method: 'GET' | 'POST' | 'PATCH' | 'DELETE'- HTTP method (required)contentType: 'application/json' | 'multipart/form-data' | 'application/merge-patch+json'- Content-Type header (required)accept: 'application/json'- Accept header (required)inputSchema: TInputSchema- Zod schema for request validation (required)outputSchema: TOutputSchema- Zod schema for response validation (required)querySchema?: ZodType<Query>- Zod schema for query parameters (optional)headersSchema?: ZodType<Headers>- Zod schema for headers (optional)
Abstract Methods:
getPath(): string- Returns the API endpoint path (required)
Built-in Methods:
validateInput(): output<TInputSchema>- Validates the request inputvalidateQuery(): Query | undefined- Validates query parametersvalidateHeaders(): Headers | undefined- Validates headersvalidateOutput(data: unknown): output<TOutputSchema>- Validates the responseparseResponse(data: unknown, rawResponse?: Response): output<TOutputSchema>- Parses and validates the response (can be overridden)
ApiExtension
type ApiExtension = Record<string, unknown>Base type for plugin extensions that add new methods to the API client.
ApiClientPlugin
interface ApiClientPlugin<T extends ApiExtension = Record<string, unknown>> {
setup: (client: ApiClient<Record<string, unknown>>) => T
}Interface for creating plugins that extend the API client functionality.
Errors
InputValidationError
class InputValidationError extends Error {
constructor(public readonly issues: ZodIssue[])
}Thrown when request input validation fails.
Properties:
issues: ZodIssue[]- Array of validation errors from Zod
OutputValidationError
class OutputValidationError extends Error {
constructor(public readonly issues: ZodIssue[])
}Thrown when response validation fails.
Properties:
issues: ZodIssue[]- Array of validation errors from Zod
Usage
Creating the API Client
import { createApiClient } from '@deliverart/sdk-js-core';
const client = createApiClient({
baseUrl: 'https://api.deliverart.com'
});Parameters:
baseUrl: string(required) - The base URL for all API requests
Creating a Custom Request
import { AbstractApiRequest } from '@deliverart/sdk-js-core';
import { z } from 'zod';
// Define input schema
const createUserInputSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.coerce.number().min(18).optional()
});
// Define output schema
const userResponseSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string(),
age: z.coerce.number().nullable(),
createdAt: z.string()
});
// Define query parameters schema (optional)
const getUsersQuerySchema = z.object({
page: z.coerce.number().optional(),
limit: z.coerce.number().optional(),
search: z.string().optional()
});
// Create the request class
class CreateUser extends AbstractApiRequest<
typeof createUserInputSchema,
typeof userResponseSchema
> {
readonly method = 'POST';
readonly contentType = 'application/json';
readonly accept = 'application/json';
readonly inputSchema = createUserInputSchema;
readonly outputSchema = userResponseSchema;
readonly querySchema = undefined;
readonly headersSchema = undefined;
constructor(input: z.input<typeof createUserInputSchema>) {
super(input);
}
getPath(): string {
return '/users';
}
}
// Request with path parameters
class GetUser extends AbstractApiRequest<
typeof z.undefined,
typeof userResponseSchema
> {
readonly method = 'GET';
readonly contentType = 'application/json';
readonly accept = 'application/json';
readonly inputSchema = z.undefined();
readonly outputSchema = userResponseSchema;
readonly querySchema = undefined;
readonly headersSchema = undefined;
private readonly userId: string;
constructor(userId: string) {
super(undefined);
this.userId = userId;
}
getPath(): string {
return `/users/${this.userId}`;
}
}
// Request with query parameters
class GetUsers extends AbstractApiRequest<
typeof z.undefined,
typeof z.array(userResponseSchema),
z.infer<typeof getUsersQuerySchema>
> {
readonly method = 'GET';
readonly contentType = 'application/json';
readonly accept = 'application/json';
readonly inputSchema = z.undefined();
readonly outputSchema = z.array(userResponseSchema);
readonly querySchema = getUsersQuerySchema;
readonly headersSchema = undefined;
constructor(options?: { query?: z.infer<typeof getUsersQuerySchema> }) {
super(undefined, options);
}
getPath(): string {
return '/users';
}
}Making API Calls
import { client } from './client';
// Create a user
const newUser = await client.call(new CreateUser({
name: 'John Doe',
email: '[email protected]',
age: 25
}));
// Get a user
const user = await client.call(new GetUser('user-123'));
// Get users with filters
const users = await client.call(new GetUsers({
query: {
page: 1,
limit: 10,
search: 'john'
}
}));Adding Middleware
Request Middleware
client.addRequestMiddleware(async (ctx) => {
console.log('Making request to:', ctx.url.toString());
// Modify headers
return {
...ctx,
init: {
...ctx.init,
headers: {
...ctx.init.headers,
'X-Custom-Header': 'value'
}
}
};
});Parameters:
ctx.url: URL- The request URLctx.init: RequestInit- The fetch init options
Return: Modified RequestContext or the original context
Response Middleware
client.addResponseMiddleware(async (parsed, requestCtx) => {
console.log('Response status:', parsed.response.status);
console.log('Response body:', parsed.body);
return parsed;
});Parameters:
parsed.response: Response- The fetch Response objectparsed.body: unknown- The parsed response bodyrequestCtx: RequestContext- The original request context
Return: Modified ParsedResponse or the original parsed response
Creating a Plugin
import { ApiClient, ApiClientPlugin, ApiExtension } from '@deliverart/sdk-js-core';
// Define the extension interface
interface LoggerExtension extends ApiExtension {
logger: {
enable: () => void;
disable: () => void;
};
}
// Create the plugin
class LoggerPlugin implements ApiClientPlugin<LoggerExtension> {
private enabled = true;
setup(client: ApiClient): LoggerExtension {
// Add request middleware
client.addRequestMiddleware(async (ctx) => {
if (this.enabled) {
console.log('[Request]', ctx.init.method, ctx.url.toString());
}
return ctx;
});
// Add response middleware
client.addResponseMiddleware(async (parsed, ctx) => {
if (this.enabled) {
console.log('[Response]', parsed.response.status);
}
return parsed;
});
// Return extension methods
return {
logger: {
enable: () => {
this.enabled = true;
},
disable: () => {
this.enabled = false;
}
}
};
}
}
// Use the plugin
const client = createApiClient({ baseUrl: 'https://api.example.com' })
.addPlugin(new LoggerPlugin());
// Now you can use the logger methods
client.logger.disable();
client.logger.enable();Error Handling
import { InputValidationError, OutputValidationError } from '@deliverart/sdk-js-core';
try {
await client.call(new CreateUser({
name: '', // Invalid: min length is 1
email: 'invalid-email', // Invalid email format
}));
} catch (error) {
if (error instanceof InputValidationError) {
console.error('Input validation failed:');
error.issues.forEach(issue => {
console.error(`- ${issue.path.join('.')}: ${issue.message}`);
});
} else if (error instanceof OutputValidationError) {
console.error('Response validation failed:');
error.issues.forEach(issue => {
console.error(`- ${issue.path.join('.')}: ${issue.message}`);
});
} else {
console.error('Other error:', error);
}
}Advanced Features
Custom Response Parsing
Override parseResponse to customize how responses are parsed:
import { Paginated, responseToPagination } from '@deliverart/sdk-js-global-types';
class GetUsers extends AbstractApiRequest</*...*/> {
// ... other properties ...
parseResponse(data: unknown, rawResponse: Response): Paginated<User> {
const users = z.array(userResponseSchema).parse(data);
return this.validateOutput({
data: users,
pagination: responseToPagination(rawResponse)
});
}
}FormData Requests
const uploadImageInputSchema = z.instanceof(FormData);
class UploadImage extends AbstractApiRequest<
typeof uploadImageInputSchema,
typeof imageResponseSchema
> {
readonly method = 'POST';
readonly contentType = 'multipart/form-data';
readonly accept = 'application/json';
readonly inputSchema = uploadImageInputSchema;
readonly outputSchema = imageResponseSchema;
constructor(formData: FormData) {
super(formData);
}
getPath(): string {
return '/images';
}
}
// Usage
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('name', 'My Image');
const image = await client.call(new UploadImage(formData));License
MIT
