UNPKG

@dbs-portal/tool-mock

Version:

API mocking toolkit using MSW for DBS Portal development workflows

303 lines 10.4 kB
/** * API client integration for seamless mocking */ import { setupMocks, getMockConfig, isMswSetup } from '../core/setup'; import { getEnvironmentInfo } from '../core/environment'; /** * Create a mock-aware API client */ export async function createMockAwareApiClient(config) { const { baseURL, mockBaseURL = baseURL, enableMocking = false, mockConfig, mockHandlers = [], timeout = 30000, headers = {}, interceptors, } = config; // Setup MSW if mocking is enabled and not already setup if (enableMocking && !isMswSetup()) { await setupMocks({ config: mockConfig || {}, handlers: mockHandlers, }); } // Create the API client implementation const client = { async get(url, requestConfig) { return makeRequest('GET', url, undefined, requestConfig); }, async post(url, data, requestConfig) { return makeRequest('POST', url, data, requestConfig); }, async put(url, data, requestConfig) { return makeRequest('PUT', url, data, requestConfig); }, async patch(url, data, requestConfig) { return makeRequest('PATCH', url, data, requestConfig); }, async delete(url, requestConfig) { return makeRequest('DELETE', url, undefined, requestConfig); }, isMocking() { return enableMocking && isMswSetup(); }, getConfig() { return config; }, updateConfig(newConfig) { Object.assign(config, newConfig); }, }; // Internal request function async function makeRequest(method, url, data, requestConfig) { const fullUrl = url.startsWith('http') ? url : `${client.isMocking() ? mockBaseURL : baseURL}${url}`; const requestHeaders = { 'Content-Type': 'application/json', ...headers, ...requestConfig?.headers, }; // Apply request interceptors let finalConfig = { method, url: fullUrl, data, headers: requestHeaders, timeout, ...requestConfig, }; if (interceptors?.request) { for (const interceptor of interceptors.request) { finalConfig = interceptor(finalConfig); } } try { // Make the actual request const response = await fetch(finalConfig.url, { method: finalConfig.method, headers: finalConfig.headers, body: finalConfig.data ? JSON.stringify(finalConfig.data) : null, signal: requestConfig?.signal, }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } let responseData = await response.json(); // Apply response interceptors if (interceptors?.response) { for (const interceptor of interceptors.response) { responseData = interceptor(responseData); } } // Handle DBS Portal API response format if (responseData.success !== undefined) { if (responseData.success) { return responseData.data; } else { throw new Error(responseData.error?.message || 'API request failed'); } } return responseData; } catch (error) { // Apply error interceptors if (interceptors?.response) { for (const interceptor of interceptors.response) { try { return interceptor({ error }); } catch { // Continue with original error } } } throw error; } } return client; } /** * Create environment-aware API client */ export async function createEnvironmentAwareApiClient(config) { const envInfo = getEnvironmentInfo(); let environmentConfig; if (envInfo.runtime.isProduction) { environmentConfig = config.production; } else if (envInfo.runtime.isTest) { environmentConfig = config.testing; } else if (config.staging && process.env['NODE_ENV'] === 'staging') { environmentConfig = config.staging; } else { environmentConfig = config.development; } // Merge with base configuration const finalConfig = { baseURL: '', enableMocking: envInfo.shouldMock, ...environmentConfig, }; return createMockAwareApiClient(finalConfig); } /** * Wrap existing HTTP client with mock capabilities */ export function wrapHttpClientWithMocks(wrapperConfig) { const { client, requestTransformer, responseTransformer, errorTransformer } = wrapperConfig; // Store original methods const originalRequest = client.request?.bind(client); const originalGet = client.get?.bind(client); const originalPost = client.post?.bind(client); const originalPut = client.put?.bind(client); const originalPatch = client.patch?.bind(client); const originalDelete = client.delete?.bind(client); // Create wrapper functions const wrapMethod = (originalMethod, method) => { return async (...args) => { try { // Apply request transformer if (requestTransformer) { args = requestTransformer({ method, args }); } const result = await originalMethod(...args); // Apply response transformer if (responseTransformer) { return responseTransformer(result); } return result; } catch (error) { // Apply error transformer if (errorTransformer) { throw errorTransformer(error); } throw error; } }; }; // Wrap methods if they exist if (originalRequest) { client.request = wrapMethod(originalRequest, 'request'); } if (originalGet) { client.get = wrapMethod(originalGet, 'GET'); } if (originalPost) { client.post = wrapMethod(originalPost, 'POST'); } if (originalPut) { client.put = wrapMethod(originalPut, 'PUT'); } if (originalPatch) { client.patch = wrapMethod(originalPatch, 'PATCH'); } if (originalDelete) { client.delete = wrapMethod(originalDelete, 'DELETE'); } // Add mock-specific methods client.isMocking = () => isMswSetup(); client.getMockConfig = () => getMockConfig(); return client; } /** * Create API client factory */ export function createApiClientFactory(defaultConfig = {}) { return { /** * Create client for specific service */ createServiceClient: async (serviceName, serviceConfig = {}) => { const config = { ...defaultConfig, ...serviceConfig, baseURL: serviceConfig.baseURL || `${defaultConfig.baseURL}/${serviceName}`, }; return createMockAwareApiClient(config); }, /** * Create client with authentication */ createAuthenticatedClient: async (token, clientConfig = {}) => { const config = { ...defaultConfig, ...clientConfig, headers: { ...defaultConfig.headers, ...clientConfig.headers, Authorization: `Bearer ${token}`, }, }; return createMockAwareApiClient(config); }, /** * Create client with custom interceptors */ createInterceptedClient: async (interceptors, clientConfig = {}) => { const config = { ...defaultConfig, ...clientConfig, interceptors: { ...defaultConfig.interceptors, ...interceptors, }, }; return createMockAwareApiClient(config); }, }; } /** * Integration with existing @dbs-portal/core-api HttpClient */ export async function integrateWithCoreApiClient(HttpClientClass, mockConfig) { // Create a new class that extends the original HttpClient class MockAwareHttpClient extends HttpClientClass { mockClient; constructor(config) { super(config); // Initialize mock client if mocking is enabled if (mockConfig?.enableMocking) { this.initializeMockClient(config, mockConfig); } } async initializeMockClient(config, mockConf) { this.mockClient = await createMockAwareApiClient({ baseURL: config.baseURL || '', ...mockConf, }); } // Override HTTP methods to use mock client when available async get(...args) { if (this.mockClient?.isMocking()) { return this.mockClient.get(...args); } return super.get(...args); } async post(...args) { if (this.mockClient?.isMocking()) { return this.mockClient.post(...args); } return super.post(...args); } async put(...args) { if (this.mockClient?.isMocking()) { return this.mockClient.put(...args); } return super.put(...args); } async patch(...args) { if (this.mockClient?.isMocking()) { return this.mockClient.patch(...args); } return super.patch(...args); } async delete(...args) { if (this.mockClient?.isMocking()) { return this.mockClient.delete(...args); } return super.delete(...args); } isMocking() { return this.mockClient?.isMocking() || false; } } return MockAwareHttpClient; } //# sourceMappingURL=api-client.js.map