netlify-api-framework
v1.0.6
Published
Modern API framework dedicated to Netlify Functions (TypeScript, Fetch API)
Maintainers
Readme
Netlify API Framework
Modern, type-safe API framework dedicated to Netlify Functions with TypeScript support and comprehensive middleware system.
🚀 Features
- TypeScript-first - Full TypeScript support with comprehensive type definitions
- Modern Fetch API - Built on web standards, no legacy dependencies
- Middleware System - Comprehensive middleware for authentication, CORS, rate limiting, and more
- Route Parameters - Dynamic route parameters with automatic parsing
- Error Handling - Built-in error handling and validation
- Performance Monitoring - Built-in performance metrics and logging
- Security - Security headers, rate limiting, and authentication middleware
- Testing - Comprehensive test suite with Vitest
- Zero Dependencies - Lightweight with minimal external dependencies
📦 Installation
npm install netlify-api-framework🚀 Quick Start
Basic Setup
Create your API function in netlify/functions/api.mts:
import { NetlifyRouter, corsMiddleware, jsonBodyParser, errorHandlingMiddleware, json } from 'netlify-api-framework'
const router = new NetlifyRouter()
// Add global middleware
router.use(corsMiddleware)
router.use(jsonBodyParser)
router.use(errorHandlingMiddleware)
// Define routes
router.get('/hello', async (req, context) => {
return json({
message: 'Hello World!',
timestamp: new Date().toISOString()
})
})
router.get('/hello/:name', async (req, context, params) => {
return json({
message: `Hello, ${params?.name}!`,
timestamp: new Date().toISOString()
})
})
// Public routes
router.get('/health', async (req, context) => {
return json({
status: 'healthy',
timestamp: new Date().toISOString(),
version: '1.0.0'
})
})
// Export handler for Netlify
export const handler = router.handler()Advanced Example with Middleware
import {
NetlifyRouter,
corsMiddleware,
jsonBodyParser,
errorHandlingMiddleware,
authMiddleware,
rateLimitMiddleware,
requestIdMiddleware,
securityHeadersMiddleware,
performanceMiddleware,
json,
parseQueryParams
} from 'netlify-api-framework'
const router = new NetlifyRouter()
// Global middleware stack
router.use(requestIdMiddleware)
router.use(securityHeadersMiddleware)
router.use(corsMiddleware)
router.use(rateLimitMiddleware)
router.use(jsonBodyParser)
router.use(performanceMiddleware)
router.use(errorHandlingMiddleware)
// Public routes
router.get('/api/health', async (req, context) => {
return json({
status: 'healthy',
timestamp: new Date().toISOString(),
version: '1.0.0'
})
})
// Protected routes
const protectedRouter = new NetlifyRouter()
protectedRouter.use(authMiddleware)
protectedRouter.get('/profile', async (req, context) => {
const user = (req as any).user // Added by auth middleware
return json({
user: {
id: user.id,
email: user.email
}
})
})
protectedRouter.post('/posts', async (req, context) => {
const body = (req as any).parsedBody
const user = (req as any).user
// Create post logic here
const post = {
id: Date.now(),
title: body.title,
content: body.content,
authorId: user.id,
createdAt: new Date().toISOString()
}
return json({ post }, { status: 201 })
})
// Mount protected routes
router.use('/api/protected', protectedRouter)
export const handler = router.handler()🛠 API Reference
Router
NetlifyRouter
Main router class for handling HTTP requests.
const router = new NetlifyRouter()
// HTTP methods
router.get(path, handler)
router.post(path, handler)
router.put(path, handler)
router.delete(path, handler)
router.patch(path, handler)
router.options(path, handler)
// Middleware
router.use(middleware)
router.use(path, subRouter)
// Get handler for Netlify
const handler = router.handler()Route Parameters
// Dynamic route with parameter
router.get('/users/:id', async (req, context, params) => {
const userId = params?.id
return json({ userId })
})
// Multiple parameters
router.get('/users/:userId/posts/:postId', async (req, context, params) => {
const { userId, postId } = params || {}
return json({ userId, postId })
})
// Query parameters
router.get('/search', async (req, context) => {
const queryParams = parseQueryParams(req)
const { q, limit, offset } = queryParams
return json({ query: q, limit, offset })
})Middleware
Built-in Middleware
import {
corsMiddleware,
jsonBodyParser,
errorHandlingMiddleware,
authMiddleware,
rateLimitMiddleware,
requestIdMiddleware,
securityHeadersMiddleware,
performanceMiddleware,
cacheMiddleware,
compressionMiddleware,
requestSizeLimitMiddleware,
loggingMiddleware
} from 'netlify-api-framework'
// CORS
router.use(corsMiddleware)
// JSON Body Parser
router.use(jsonBodyParser)
// Authentication
router.use(authMiddleware)
// Rate Limiting
router.use(rateLimitMiddleware)
// Security Headers
router.use(securityHeadersMiddleware)
// Performance Monitoring
router.use(performanceMiddleware)
// Request Size Limit
router.use(requestSizeLimitMiddleware)
// Caching
router.use(cacheMiddleware)
// Compression
router.use(compressionMiddleware)
// Logging
router.use(loggingMiddleware)Custom Middleware
import { Middleware } from 'netlify-api-framework'
const customAuth: Middleware = async (req, context, next) => {
const authHeader = req.headers.get('Authorization')
if (!authHeader) {
return new Response('Unauthorized', { status: 401 })
}
// Add user to request
(req as any).user = { id: 1, email: '[email protected]' }
return next()
}
router.use(customAuth)Utilities
import {
json,
text,
html,
parseQueryParams,
validateFields,
createErrorResponse,
consoleFormat
} from 'netlify-api-framework'
// JSON Response
return json({ data: 'value' }, 200)
// Text Response
return text('Hello World', 200)
// HTML Response
return html('<h1>Hello World</h1>', 200)
// Parse Query Parameters
const params = parseQueryParams(req)
// Validate Fields
const validation = validateFields(body, ['name', 'email'])
if (!validation.isValid) {
return createErrorResponse(400, 'Missing fields', { missing: validation.missing })
}
// Logging
console.log(consoleFormat('info', 'Request processed', { requestId: '123' }))🧪 Testing
The framework includes comprehensive tests. Run them with:
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run framework tests only
npm run test:framework
# Run tests in watch mode
npm run test:framework:watch
# Run tests with UI
npm run test:uiWriting Tests
import { describe, it, expect } from 'vitest'
import { NetlifyRouter, json } from 'netlify-api-framework'
describe('API Routes', () => {
it('should handle GET request', async () => {
const router = new NetlifyRouter()
router.get('/test', async (req, context) => {
return json({ message: 'test' })
})
const handler = router.handler()
const request = new Request('http://localhost/.netlify/functions/api/test')
const context = {} as any
const response = await handler(request, context)
const data = await response.json()
expect(response.status).toBe(200)
expect(data.message).toBe('test')
})
})🏗 Project Structure
netlify/
├── functions/
│ └── api.mts # Main API function
├── framework/ # Framework source code
│ ├── index.ts # Main exports
│ ├── middleware/ # Middleware modules
│ ├── router/ # Router implementation
│ ├── types/ # TypeScript types
│ ├── utils/ # Utility functions
│ └── tests/ # Test files
└── project/ # Your application code
├── controllers/ # Route controllers
├── routes/ # Route definitions
└── types/ # Application types🔧 Configuration
TypeScript Configuration
The framework uses TypeScript with ES modules. Make sure your tsconfig.json includes:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"skipLibCheck": true
}
}Netlify Configuration
In your netlify.toml:
[build]
functions = "netlify/functions"
[functions]
directory = "netlify/functions"
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/api/:splat"
status = 200🚀 Deployment
Publishing to NPM
The framework includes automated publishing scripts:
Using the automated script:
# Interactive publish with version selection
./publish.sh
# Quick patch version publish
./quick-publish.shManual publish process:
# Clean and test
npm run clean
npm run test:run
# Build the package
npm run build
# Test the build
npm run publish:dry
# Version bump (optional)
npm run version:patch # or version:minor, version:major
# Publish
npm publishDeploying to Netlify
Build your project:
npm run buildDeploy to Netlify:
netlify deploy --prod
📝 Examples
REST API with CRUD Operations
import { NetlifyRouter, json, jsonBodyParser, errorHandlingMiddleware, parseQueryParams } from 'netlify-api-framework'
const router = new NetlifyRouter()
router.use(jsonBodyParser)
router.use(errorHandlingMiddleware)
// In-memory store (use database in production)
const posts = new Map()
// GET /api/posts - List all posts
router.get('/api/posts', async (req, context) => {
const queryParams = parseQueryParams(req)
const limit = parseInt(queryParams.limit || '10')
const offset = parseInt(queryParams.offset || '0')
const allPosts = Array.from(posts.values())
const paginatedPosts = allPosts.slice(offset, offset + limit)
return json({
posts: paginatedPosts,
total: allPosts.length,
limit,
offset
})
})
// GET /api/posts/:id - Get single post
router.get('/api/posts/:id', async (req, context, params) => {
const post = posts.get(params?.id)
if (!post) {
return json({ error: 'Post not found' }, 404)
}
return json({ post })
})
// POST /api/posts - Create new post
router.post('/api/posts', async (req, context) => {
const body = (req as any).parsedBody
if (!body.title || !body.content) {
return json({ error: 'Title and content are required' }, 400)
}
const post = {
id: Date.now().toString(),
title: body.title,
content: body.content,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
}
posts.set(post.id, post)
return json({ post }, 201)
})
// PUT /api/posts/:id - Update post
router.put('/api/posts/:id', async (req, context, params) => {
const post = posts.get(params?.id)
if (!post) {
return json({ error: 'Post not found' }, 404)
}
const body = (req as any).parsedBody
const updatedPost = {
...post,
...body,
updatedAt: new Date().toISOString()
}
posts.set(post.id, updatedPost)
return json({ post: updatedPost })
})
// DELETE /api/posts/:id - Delete post
router.delete('/api/posts/:id', async (req, context, params) => {
const exists = posts.has(params?.id)
if (!exists) {
return json({ error: 'Post not found' }, 404)
}
posts.delete(params?.id)
return json({ message: 'Post deleted successfully' })
})
export const handler = router.handler()🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built for Netlify Functions
- Inspired by modern web standards
- TypeScript-first approach
- Comprehensive testing with Vitest
