
Tired of vendor lock-in? FMiddleware is a framework-agnostic HTTP middleware that lets you write your API once and deploy it anywhere—AWS Lambda, Express.js, or Docker containers.
You started with AWS Lambda even used a framework like Serverless.com. It made sense—no servers to manage, pay-per-use pricing, and quick deployments. Life was good.
Then you tried to debug something locally.
The reality is that local development with Lambda is painful. You're constantly dealing with mocked API Gateway events, environment differences between local and deployed code, and debugging workflows that don't match how you'd normally work with Node.js. When something breaks in production, reproducing it locally means wrestling with event structures and Lambda-specific context objects.
And if your team ever decides to move to Docker or Kubernetes? Your entire codebase is tied to Lambda's event structure—migration means rewriting your API layer.
What if you could write your API handlers once and deploy them to any runtime without changing a single line of business logic?
That's exactly what FMiddleware does.
FMiddleware is a framework-agnostic HTTP middleware library that abstracts away the runtime differences between AWS Lambda and Express.js. Your handlers stay the same—only the deployment wrapper changes.
Install the package:
npm install @loupeat/fmiddleware
Define your API handler once:
import { FRequest } from "@loupeat/fmiddleware";
interface Note {
id: string;
title: string;
}
// This handler works on BOTH Lambda and Express
api.get("/api/notes", async (request: FRequest<any, any>) => {
const notes: Note[] = [{ id: "1", title: "Hello World" }];
return api.responses.OK<any, Note[]>(request, notes);
});
import express from "express";
import { FExpressMiddleware, FRequest } from "@loupeat/fmiddleware";
const app = express();
const api = new FExpressMiddleware();
// Register your routes (same as above)
api.get("/api/notes", async (request: FRequest<any, any>) => {
const notes = [{ id: "1", title: "Hello World" }];
return api.responses.OK(request, notes);
});
// Use FMiddleware as Express middleware
app.use(express.json());
app.all("*", async (req, res) => {
const response = await api.process(req);
res.status(response.statusCode).json(response.body);
});
app.listen(3000);
import { APIGatewayProxyHandler } from "aws-lambda";
import { FAWSLambdaMiddleware, FRequest } from "@loupeat/fmiddleware";
const api = new FAWSLambdaMiddleware();
// Same exact handler code!
api.get("/api/notes", async (request: FRequest<any, any>) => {
const notes = [{ id: "1", title: "Hello World" }];
return api.responses.OK(request, notes);
});
export const handler: APIGatewayProxyHandler = async (event) => {
return api.process(event);
};
Notice something? The handler code is identical. Only the wrapper changes.
No more mocking Lambda events or fighting with local emulators. Just run your Express server locally and test like any normal Node.js app:
npm run dev # Uses Express wrapper
When you're ready for production, deploy with your Lambda wrapper—zero code changes.
Already on Lambda and want to move to Docker? Simply:
FAWSLambdaMiddleware for FExpressMiddlewareYour handlers, validation, authentication—everything stays the same.
Running some endpoints on Lambda for cost efficiency and others on ECS for performance? FMiddleware lets you share the exact same handler code across both.
FMiddleware isn't just a wrapper—it's a full-featured API toolkit:
Full type safety for requests and responses:
interface CreateNoteRequest {
title: string;
content: string;
}
api.post<any, CreateNoteRequest>("/api/notes", async (request) => {
const { title, content } = request.body; // Fully typed!
// ...
});
const CreateNoteSchema = {
type: "object",
properties: {
title: { type: "string", minLength: 1 },
content: { type: "string" },
},
required: ["title", "content"]
};
api.post("/api/notes", async (request) => {
// request.body is automatically validated
const { title, content } = request.body;
// ...
}, CreateNoteSchema);
const AuthPreProcessor: RequestPreProcessor = {
name: "AuthPreProcessor",
pathPatterns: ["/api/notes/*"],
requestSources: "*", // Works on both Express and Lambda
process: async ({ request }) => {
const authHeader = request.headers["authorization"];
if (!authHeader) {
throw new AuthenticationError("Missing authorization header");
}
const token = authHeader.replace(/Bearer /, "");
const user = await authService.verifyToken(token);
request.context["user"] = user;
}
};
api.addRequestPreProcessor(AuthPreProcessor);
import {
ValidationError, // 400 Bad Request
AuthenticationError, // 401 Unauthorized
ForbiddenError, // 403 Forbidden
NotFoundError, // 404 Not Found
ConflictError, // 409 Conflict
} from "@loupeat/fmiddleware";
// Errors automatically map to correct HTTP status codes
if (!note) {
throw new NotFoundError(`Note ${noteId} not found`);
}
Automatically generate OpenAPI 3.0 specs from your handlers:
import { FExpressMiddleware, OpenAPIMetadata } from "@loupeat/fmiddleware";
api.get("/api/notes", async (request) => {
const notes = await notesService.list();
return api.responses.OK(request, notes);
}, {
summary: "List all notes",
description: "Retrieves all notes for the authenticated user",
tags: ["Notes"],
});
FMiddleware works with any deployment tool—Serverless Framework, AWS CDK, SST, or plain CloudFormation. Here's an example using Serverless Framework:
service: notes-api
plugins:
- serverless-esbuild
provider:
name: aws
runtime: nodejs20.x
region: eu-west-1
functions:
api:
handler: src/handler.main
events:
- http:
method: any
path: "api/{proxy+}"
cors: true
timeout: 15
FMiddleware is perfect if you:
npm install @loupeat/fmiddleware
# For AWS Lambda support
npm install --save-dev @types/aws-lambda
Check out the full documentation and examples:
Have you dealt with serverless lock-in? How did you handle the migration? I'd love to hear your experiences in the comments!
FMiddleware is open source and MIT licensed. Contributions welcome!
gemmaI ported the whole Gemma-4 family — E2B, E4B, 12B, 31B, and the 26B-A4B MoE — to run on...
communityHey DEV, I'm Tobore. Let's actually connect. I've been on here for a while now, mostly writing and...
ai(yep, kinda clickbait, just for the funsies 😊) At the beginning of the year, I relaunched my...
aiMy laptop was sitting idle with the fan at full tilt. Nothing was running that I knew of. The culprit...
githubactionsI Built a Thing! TL;DR — Google Gemini-based Pull Request reviews and Issue Triaging for...
aiI've been hearing the word "harness" thrown around a lot lately. I assumed it just meant "the IDE" or...
Workflows from the Neura Market marketplace related to this DeepSeek resource