Skip to content

travishorn/multi-format-data-portal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multi-Format Data Portal

A flexible, extensible Node.js API server built with Fastify that serves CSV data in multiple formats through HTTP content negotiation. The server automatically converts your data to the format requested by the client via the Accept header.

Features

  • Serve the same data in multiple formats (CSV, JSON, XLSX, Markdown, HTML, PDF, XML, GeoJSON, SQL)
  • Clients request formats using HTTP Accept headers
  • Link headers in responses inform clients about available formats
  • Easy to add new formats by implementing the FormatConverter interface
  • Configure which formats are available for each resource
  • Data is cached for optimal performance
  • Full JSDoc type annotations
  • Error handling, graceful shutdown, health checks

Supported Formats

Format MIME Type Extension Description
CSV text/csv csv Standard comma-separated values format
JSON application/json json JSON array of objects
XLSX application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx Excel spreadsheet with auto-sized columns
Markdown text/markdown md Markdown table with automatic numeric column alignment and padding
HTML text/html html Fully styled HTML document with responsive table
PDF application/pdf pdf Multi-page PDF with headers, footers, and formatted tables
XML application/xml xml XML document with sanitized element names
GeoJSON application/geo+json geojson GeoJSON FeatureCollection with automatic coordinate detection
SQL text/x-sql sql SQL CREATE TABLE and INSERT statements with type inference

Installation

npm install

Usage

Start the Server

npm start

Or for development with auto-reload:

npm run dev

The server starts on http://localhost:3000 by default.

Request Data in Different Formats

The API uses HTTP content negotiation. Send an Accept header with your preferred MIME type:

JSON (default for API clients)

curl http://localhost:3000/resources/mlb-ball-parks
# or explicitly:
curl -H "Accept: application/json" http://localhost:3000/resources/mlb-ball-parks

CSV

curl -H "Accept: text/csv" http://localhost:3000/resources/mlb-ball-parks

XLSX

curl -H "Accept: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" \
  http://localhost:3000/resources/mlb-ball-parks \
  --output mlb-ball-parks.xlsx

Markdown

curl -H "Accept: text/markdown" http://localhost:3000/resources/mlb-ball-parks

HTML

curl -H "Accept: text/html" http://localhost:3000/resources/mlb-ball-parks

PDF

curl -H "Accept: application/pdf" \
  http://localhost:3000/resources/mlb-ball-parks \
  --output mlb-ball-parks.pdf

XML

curl -H "Accept: application/xml" http://localhost:3000/resources/mlb-ball-parks

GeoJSON

curl -H "Accept: application/geo+json" http://localhost:3000/resources/mlb-ball-parks

SQL

curl -H "Accept: text/x-sql" http://localhost:3000/resources/mlb-ball-parks

Using File Extensions

Alternatively, you can specify the format using a file extension in the URL:

curl http://localhost:3000/resources/mlb-ball-parks.json
curl http://localhost:3000/resources/mlb-ball-parks.csv
curl http://localhost:3000/resources/mlb-ball-parks.xlsx
curl http://localhost:3000/resources/mlb-ball-parks.md
curl http://localhost:3000/resources/mlb-ball-parks.html
curl http://localhost:3000/resources/mlb-ball-parks.pdf
curl http://localhost:3000/resources/mlb-ball-parks.xml
curl http://localhost:3000/resources/mlb-ball-parks.geojson
curl http://localhost:3000/resources/mlb-ball-parks.sql

Discover Available Formats

Use an OPTIONS request or check the Link header in any response:

# OPTIONS request
curl -X OPTIONS http://localhost:3000/resources/mlb-ball-parks

# Check Link header in response
curl -I http://localhost:3000/resources/mlb-ball-parks

The Link header contains all available formats:

Link: </resources/mlb-ball-parks.csv>; rel="alternate"; type="text/csv",
      </resources/mlb-ball-parks.json>; rel="alternate"; type="application/json",
      </resources/mlb-ball-parks.xlsx>; rel="alternate"; type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      ...

API Documentation

Endpoints

GET /

Returns API information.

Response:

{
  "name": "Multi-format Data Portal",
  "version": "1.0.0",
  "description": "Data portal API for serving data in multiple formats",
  "endpoints": {
    "resources": "/resources/:resourceName",
    "health": "/health"
  }
}

GET /health

Health check endpoint.

Response:

{
  "status": "ok"
}

GET /resources/:resourceName

Returns resource data in the requested format based on the Accept header.

Parameters:

  • resourceName (path): Name of the resource (e.g., mlb-ball-parks)

Headers:

  • Accept: MIME type of desired format (optional, defaults to JSON)

Response:

  • Content type varies based on Accept header
  • Link header includes all available formats
  • For XLSX and PDF: Content-Disposition header suggests filename

Status Codes:

  • 200: Success
  • 404: Resource not found
  • 406: No acceptable format found

GET /resources/:resourceName.:extension

Returns resource data in the specified format via file extension.

Parameters:

  • resourceName (path): Name of the resource
  • extension (path): File extension (e.g., csv, json, xlsx, md, html, pdf, xml, geojson, sql)

Response: Same as GET /resources/:resourceName but format is determined by extension.

OPTIONS /resources/:resourceName

Returns available formats and HTTP methods for the resource.

Response:

  • Allow header: Available HTTP methods
  • Link header: All available formats with their URLs

Architecture

Key Components

Format Converters

All format converters extend the FormatConverter base class and implement:

  • getMimeType(): Returns the primary MIME type
  • getExtension(): Returns the file extension
  • getAlternativeMimeTypes(): Returns alternative MIME types (optional)
  • getName(): Returns a human-readable name
  • convert(data, options): Converts data array to Buffer

Format Registry

The FormatRegistry manages all available format converters and provides:

  • Registration of new converters
  • MIME type lookup
  • Best match selection based on Accept headers

Resource Registry

The ResourceRegistry manages data resources:

  • Maps resource names to CSV files
  • Configures which formats are available per resource
  • Stores resource descriptions

Content Negotiation Plugin

Fastify plugin that:

  • Parses Accept headers (including quality values)
  • Selects the best matching format
  • Generates Link headers for format discovery

Extending the System

Adding a New Format

  1. Create a new converter class in src/lib/formats/:
import { FormatConverter } from "./base.js";

export class MyFormatConverter extends FormatConverter {
  getMimeType() {
    return "application/my-format";
  }

  getExtension() {
    return "myformat";
  }

  getName() {
    return "My Format";
  }

  async convert(data, options = {}) {
    // Convert data array to your format
    const output = /* your conversion logic */;
    return Buffer.from(output, "utf-8");
  }
}
  1. Register it in src/lib/formats/registry.js:
import { MyFormatConverter } from "./myformat.js";

// In the constructor, add to defaultFormats:
this.defaultFormats = [
  // ... existing formats
  new MyFormatConverter(),
];
  1. The format is now available for all resources.

Adding a New Resource

Edit src/lib/resources.js and add to the constructor:

this.register("myresource", {
  csvPath: "public/myresource.csv",
  availableFormats: formatRegistry.getAllConverters(), // or specify specific formats
  description: "Description of my resource",
});

Place your CSV file in src/public/ and it will be automatically loaded and cached.

Development

Scripts

  • npm start: Start the production server
  • npm run dev: Start with auto-reload (uses node --watch)
  • npm run lint: Run ESLint
  • npm run format: Format code with Prettier
  • npm run types: Run TypeScript type checking (on JSDoc annotations)

Environment Variables

  • PORT: Server port (default: 3000)
  • HOST: Server host (default: 0.0.0.0)
  • LOG_LEVEL: Logging level (default: info)
  • NODE_ENV: Environment (development enables pretty logging)

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published