const { ContentNegotiator, ResponseFormatter } = require('edge-utils/content-negotiation');
// REST API with full content negotiation
class RESTAPI {
constructor() {
this.negotiator = new ContentNegotiator({
supportedTypes: [
'application/json',
'application/xml',
'application/vnd.api+json',
'text/csv'
],
defaultType: 'application/json'
});
this.formatter = new ResponseFormatter({
compression: true,
json: { prettyPrint: false },
xml: { rootElement: 'api-response' }
});
}
async handleRequest(request) {
const url = new URL(request.url);
const contentType = this.negotiator.negotiate(request);
try {
let data;
// Route based on path
switch (url.pathname) {
case '/api/users':
data = await this.getUsers(request);
break;
case '/api/orders':
data = await this.getOrders(request);
break;
default:
return new Response('Not found', { status: 404 });
}
// Format response
const response = await this.formatter.format(data, {
contentType,
status: 200,
headers: {
'X-API-Version': '1.0',
'Cache-Control': 'public, max-age=300'
}
});
return response;
} catch (error) {
// Format error response
const errorData = {
error: {
code: error.code || 'INTERNAL_ERROR',
message: error.message,
details: error.details
}
};
const errorResponse = await this.formatter.format(errorData, {
contentType,
status: error.status || 500
});
return errorResponse;
}
}
async getUsers(request) {
// Simulate data fetching
const users = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];
// Apply content type specific transformations
const contentType = this.negotiator.negotiate(request);
if (contentType === 'text/csv') {
// CSV format doesn't need object transformation
return users;
}
// JSON/XML format
return {
users,
metadata: {
total: users.length,
page: 1,
links: {
self: '/api/users',
next: '/api/users?page=2'
}
}
};
}
}
const api = new RESTAPI();
const handler = (request) => api.handleRequest(request);