README
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
@gograb-space/mock-api
A comprehensive HTTP interceptor library for Angular 20 applications, designed for development, testing, and prototyping with intelligent storage integration and AI-friendly APIs.
🚀 Quick Start for AI Code Generators
Installation & Setup Pattern
// app.config.ts - Standard Angular 20 Configuration
import { ApplicationConfig, APP_INITIALIZER } from '@angular/core';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import {
mockHttpInterceptor,
MockInterceptorUtilsService,
UsersMock,
ProductsMock
} from '@gograb-space/mock-api';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(withInterceptors([mockHttpInterceptor])),
{
provide: APP_INITIALIZER,
multi: true,
deps: [MockInterceptorUtilsService],
useFactory: (utils: MockInterceptorUtilsService) => () => {
utils.configureMockInterceptor(
{
enabled: true,
delay: [100, 300],
fallbackToNetwork: false,
logging: { enabled: true, level: 'info' }
},
{ ...UsersMock, ...ProductsMock }
);
return Promise.resolve();
}
}
]
};
Basic Mock Definition Pattern
// Pattern for creating mock definitions
import { MockDefinition, MockRequest, MockResponse } from '@gograb-space/mock-api';
export const EntityMock: MockDefinition = {
'GET /api/entities': (req: MockRequest): MockResponse => ({
status: 200,
data: { entities: [], total: 0 }
}),
'GET /api/entities/:id': (req: MockRequest): MockResponse => ({
status: 200,
data: { id: req.params.id, name: 'Entity' }
}),
'POST /api/entities': (req: MockRequest): MockResponse => ({
status: 201,
data: { ...req.body, id: Date.now() }
}),
'PUT /api/entities/:id': (req: MockRequest): MockResponse => ({
status: 200,
data: { ...req.body, id: req.params.id }
}),
'DELETE /api/entities/:id': (req: MockRequest): MockResponse => ({
status: 204,
data: null
})
};
📚 Core API Reference
Types
// Essential types for AI code generation
interface MockRequest {
method: string;
url: string;
params: Record<string, string>; // URL parameters (:id)
query: Record<string, string>; // Query parameters (?page=1)
body: any; // Request body
headers: Record<string, string>; // Request headers
timestamp?: number;
requestId?: string;
}
interface MockResponse {
status: number; // HTTP status code
data: any; // Response data
headers?: Record<string, string>; // Response headers
delay?: number; // Custom delay in ms
statusText?: string; // HTTP status text
}
type MockHandler = (req: MockRequest) => MockResponse | Promise<MockResponse> | Observable<MockResponse>;
type MockDefinition = Record<string, MockHandler>;
// Configuration interface for AI generators
interface GlobalInterceptorConfig {
enabled: boolean;
baseURL?: string;
delay?: number | [number, number];
fallbackToNetwork?: boolean;
logging?: {
enabled: boolean;
level: 'debug' | 'info' | 'warn' | 'error';
logRequests?: boolean;
logResponses?: boolean;
};
persistence?: {
enabled: boolean;
ttl?: number;
storage?: 'indexeddb' | 'localstorage' | 'memory' | 'intelligent';
};
middleware?: MockMiddleware[];
defaultHeaders?: Record<string, string>;
}
Service Injection Pattern
// Standard Angular 20 service pattern with mock-api
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class EntityService {
private http = inject(HttpClient);
getEntities(params?: { page?: number; limit?: number }): Observable<EntityResponse> {
return this.http.get<EntityResponse>('/api/entities', { params });
}
getEntity(id: string): Observable<Entity> {
return this.http.get<Entity>(`/api/entities/${id}`);
}
createEntity(entity: CreateEntityRequest): Observable<Entity> {
return this.http.post<Entity>('/api/entities', entity);
}
updateEntity(id: string, entity: UpdateEntityRequest): Observable<Entity> {
return this.http.put<Entity>(`/api/entities/${id}`, entity);
}
deleteEntity(id: string): Observable<void> {
return this.http.delete<void>(`/api/entities/${id}`);
}
}
🛠️ Advanced Features
Data Generation with DataGenerator
import { DataGenerator, MockDefinition } from '@gograb-space/mock-api';
const generator = DataGenerator.getInstance();
export const ProductsMock: MockDefinition = {
'GET /api/products': (req: MockRequest): MockResponse => {
const count = parseInt(req.query.limit || '10');
const products = generator.generateArray(() => generator.generateProduct(), count);
return {
status: 200,
data: {
products,
total: products.length,
pagination: {
page: parseInt(req.query.page || '1'),
limit: count
}
}
};
}
};
// Available generators
const user = generator.generateUser();
const product = generator.generateProduct();
const address = generator.generateAddress();
const phone = generator.generatePhone();
const array = generator.generateArray(() => generator.generateUser(), 10);
Runtime Mock Management
import { Component, inject } from '@angular/core';
import { MockInterceptorUtilsService } from '@gograb-space/mock-api';
@Component({
selector: 'app-admin',
template: `
<button (click)="enableTestMode()">Enable Test Mode</button>
<button (click)="disableInterceptor()">Disable Mocks</button>
`,
standalone: true
})
export class AdminComponent {
private mockUtils = inject(MockInterceptorUtilsService);
enableTestMode(): void {
const testMocks = {
'GET /api/test-data': () => ({ status: 200, data: { test: true } })
};
this.mockUtils.updateMocks(testMocks);
}
disableInterceptor(): void {
this.mockUtils.setEnabled(false);
}
getStats() {
return this.mockUtils.getStats();
}
}
Middleware System
import { MockMiddleware, MiddlewareFactory } from '@gograb-space/mock-api';
// Pre-built middleware
const loggingMiddleware = MiddlewareFactory.createLoggingMiddleware({
logRequests: true,
logResponses: true
});
const corsMiddleware = MiddlewareFactory.createCorsMiddleware({
origin: '*',
credentials: true
});
// Custom middleware pattern
const authMiddleware: MockMiddleware = {
name: 'auth',
priority: 800,
onRequest: (request) => ({
...request,
headers: {
...request.headers,
'Authorization': request.headers['Authorization'] || 'Bearer mock-token'
}
}),
onResponse: (response, request) => ({
...response,
headers: {
...response.headers,
'X-Mock-Auth': 'true'
}
})
};
🔧 Common Patterns for AI Generation
CRUD Operations Pattern
// Template for generating CRUD mocks
function createCrudMocks<T>(
entityName: string,
basePath: string,
generator: () => T,
initialData: T[] = []
): MockDefinition {
let data = [...initialData];
let nextId = data.length + 1;
return {
[`GET ${basePath}`]: (req: MockRequest): MockResponse => ({
status: 200,
data: {
items: data,
total: data.length,
page: parseInt(req.query.page || '1'),
limit: parseInt(req.query.limit || '10')
}
}),
[`GET ${basePath}/:id`]: (req: MockRequest): MockResponse => {
const item = data.find(d => d.id === req.params.id);
return item
? { status: 200, data: item }
: { status: 404, data: { error: `${entityName} not found` } };
},
[`POST ${basePath}`]: (req: MockRequest): MockResponse => {
const newItem = { ...req.body, id: nextId++ };
data.push(newItem);
return { status: 201, data: newItem };
},
[`PUT ${basePath}/:id`]: (req: MockRequest): MockResponse => {
const index = data.findIndex(d => d.id === req.params.id);
if (index === -1) {
return { status: 404, data: { error: `${entityName} not found` } };
}
data[index] = { ...data[index], ...req.body };
return { status: 200, data: data[index] };
},
[`DELETE ${basePath}/:id`]: (req: MockRequest): MockResponse => {
const index = data.findIndex(d => d.id === req.params.id);
if (index === -1) {
return { status: 404, data: { error: `${entityName} not found` } };
}
data.splice(index, 1);
return { status: 204, data: null };
}
};
}
// Usage
export const ProductsMock = createCrudMocks(
'Product',
'/api/products',
() => generator.generateProduct(),
initialProducts
);
Error Handling Patterns
// Standard error responses for AI generation
const ErrorResponses = {
notFound: (resource: string, id: string): MockResponse => ({
status: 404,
data: {
error: 'Not Found',
message: `${resource} with ID ${id} not found`,
code: `${resource.toUpperCase()}_NOT_FOUND`
}
}),
validationError: (fields: Record<string, string>): MockResponse => ({
status: 400,
data: {
error: 'Validation Error',
message: 'Invalid input data',
code: 'VALIDATION_ERROR',
fields
}
}),
conflict: (message: string): MockResponse => ({
status: 409,
data: {
error: 'Conflict',
message,
code: 'RESOURCE_CONFLICT'
}
}),
unauthorized: (): MockResponse => ({
status: 401,
data: {
error: 'Unauthorized',
message: 'Authentication required',
code: 'NOT_AUTHENTICATED'
}
}),
forbidden: (): MockResponse => ({
status: 403,
data: {
error: 'Forbidden',
message: 'Insufficient permissions',
code: 'ACCESS_DENIED'
}
})
};
Pagination Pattern
// Reusable pagination logic
function createPaginatedResponse<T>(
items: T[],
page: number = 1,
limit: number = 10
): { data: T[]; pagination: PaginationInfo } {
const startIndex = (page - 1) * limit;
const endIndex = startIndex + limit;
const paginatedItems = items.slice(startIndex, endIndex);
const totalPages = Math.ceil(items.length / limit);
return {
data: paginatedItems,
pagination: {
page,
limit,
total: items.length,
totalPages,
hasNext: page < totalPages,
hasPrev: page > 1
}
};
}
interface PaginationInfo {
page: number;
limit: number;
total: number;
totalPages: number;
hasNext: boolean;
hasPrev: boolean;
}
📋 Code Generation Templates
Entity Mock Template
// Template for AI to generate entity-specific mocks
export const {{EntityName}}Mock: MockDefinition = {
'GET /api/{{entityPath}}': (req: MockRequest): MockResponse => {
const page = parseInt(req.query.page || '1');
const limit = parseInt(req.query.limit || '10');
const search = req.query.search || '';
// Apply search filter if needed
let filtered{{EntityName}}s = {{entityName}}sDB;
if (search) {
filtered{{EntityName}}s = {{entityName}}sDB.filter(item =>
item.name.toLowerCase().includes(search.toLowerCase())
);
}
const { data, pagination } = createPaginatedResponse(filtered{{EntityName}}s, page, limit);
return {
status: 200,
data: { {{entityName}}s: data, pagination }
};
},
'GET /api/{{entityPath}}/:id': (req: MockRequest): MockResponse => {
const {{entityName}} = {{entityName}}sDB.find(item => item.id === req.params.id);
return {{entityName}}
? { status: 200, data: { {{entityName}} } }
: ErrorResponses.notFound('{{EntityName}}', req.params.id);
},
'POST /api/{{entityPath}}': (req: MockRequest): MockResponse => {
// Validation
const required = ['{{requiredField1}}', '{{requiredField2}}'];
const missing = required.filter(field => !req.body[field]);
if (missing.length > 0) {
const fields = missing.reduce((acc, field) => {
acc[field] = 'Required';
return acc;
}, {} as Record<string, string>);
return ErrorResponses.validationError(fields);
}
const new{{EntityName}} = {
...req.body,
id: next{{EntityName}}Id++,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
{{entityName}}sDB.push(new{{EntityName}});
return {
status: 201,
data: { {{entityName}}: new{{EntityName}} },
headers: { Location: `/api/{{entityPath}}/${new{{EntityName}}.id}` }
};
},
'PUT /api/{{entityPath}}/:id': (req: MockRequest): MockResponse => {
const index = {{entityName}}sDB.findIndex(item => item.id === req.params.id);
if (index === -1) {
return ErrorResponses.notFound('{{EntityName}}', req.params.id);
}
{{entityName}}sDB[index] = {
...{{entityName}}sDB[index],
...req.body,
updatedAt: new Date().toISOString()
};
return {
status: 200,
data: { {{entityName}}: {{entityName}}sDB[index] }
};
},
'DELETE /api/{{entityPath}}/:id': (req: MockRequest): MockResponse => {
const index = {{entityName}}sDB.findIndex(item => item.id === req.params.id);
if (index === -1) {
return ErrorResponses.notFound('{{EntityName}}', req.params.id);
}
const deleted{{EntityName}} = {{entityName}}sDB.splice(index, 1)[0];
return {
status: 200,
data: {
message: '{{EntityName}} deleted successfully',
deleted{{EntityName}}: { id: deleted{{EntityName}}.id }
}
};
}
};
// Initialize data
let {{entityName}}sDB = DataGenerator.getInstance()
.generateArray(() => DataGenerator.getInstance().generate{{EntityName}}(), 50);
let next{{EntityName}}Id = {{entityName}}sDB.length + 1;
🚀 Quick Commands for Development
# Generate new mock
npx nx g @nx/angular:service {{entity-name}}-mock --project=mock-api --no-spec
# Run tests
npx nx test mock-api
# Build library
npx nx build mock-api
# Lint code
npx nx lint mock-api
🔍 Debugging and Testing
// Debug utilities
import { MockInterceptorUtilsService } from '@gograb-space/mock-api';
const mockUtils = inject(MockInterceptorUtilsService);
// Get interceptor statistics
const stats = mockUtils.getStats();
console.log('Total requests:', stats.totalRequests);
console.log('Requests by route:', stats.requestsByRoute);
// Clear all mocks
mockUtils.clearMocks();
// Enable/disable at runtime
mockUtils.setEnabled(false); // Disable mocks
mockUtils.setEnabled(true); // Enable mocks
🎯 Integration Examples
Testing Integration
// TestBed configuration
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideHttpClient(withInterceptors([mockHttpInterceptor])),
MockInterceptorUtilsService
]
});
const mockUtils = TestBed.inject(MockInterceptorUtilsService);
mockUtils.configureMockInterceptor(
{ enabled: true, fallbackToNetwork: false },
TestMocks
);
});
Environment-based Configuration
// environments/environment.ts
export const environment = {
production: false,
mockApi: {
enabled: true,
delay: [100, 300],
logging: true
}
};
// app.config.ts
utils.configureMockInterceptor({
enabled: environment.mockApi.enabled,
delay: environment.mockApi.delay,
logging: { enabled: environment.mockApi.logging }
}, mocks);
This documentation provides comprehensive patterns and templates optimized for AI code generators, enabling rapid development of mock APIs with consistent structure and best practices.