@gasket/request Examples
This document provides working examples for all exported functions, classes, and utilities from @gasket/request.
GasketRequest
The GasketRequest class represents a normalized request object.
import { GasketRequest } from '@gasket/request';
// Create a new GasketRequest instance
const gasketRequest = new GasketRequest({
headers: {
'content-type': 'application/json',
'user-agent': 'Mozilla/5.0'
},
cookies: {
sessionId: 'abc123',
theme: 'dark'
},
query: {
page: '1',
limit: '10'
},
path: '/api/users'
});
console.log(gasketRequest.headers['content-type']); // 'application/json'
console.log(gasketRequest.cookies.sessionId); // 'abc123'
console.log(gasketRequest.query.page); // '1'
console.log(gasketRequest.path); // '/api/users'
makeGasketRequest
Converts various request-like objects into a normalized GasketRequest.
Express Request
import express from 'express';
import { makeGasketRequest } from '@gasket/request';
const app = express();
app.get('/users', async (req, res) => {
// Convert Express request to GasketRequest
const gasketRequest = await makeGasketRequest(req);
console.log(gasketRequest.headers);
console.log(gasketRequest.cookies);
console.log(gasketRequest.query);
console.log(gasketRequest.path);
console.log(gasketRequest.method); // 'GET'
res.json({ success: true });
});
Next.js Request
import { NextRequest } from 'next/server';
import { makeGasketRequest } from '@gasket/request';
export async function middleware(request) {
// Convert NextRequest to GasketRequest
const gasketRequest = await makeGasketRequest(request);
console.log(gasketRequest.path);
console.log(gasketRequest.query);
console.log(gasketRequest.cookies);
console.log(gasketRequest.method); // 'GET'
return NextResponse.next();
}
Custom Request Object
import { makeGasketRequest } from '@gasket/request';
// Create from minimal request-like object
const requestLike = {
headers: {
'authorization': 'Bearer token123',
'content-type': 'application/json'
},
url: '/api/data?filter=active&sort=name',
cookies: {
sessionId: 'xyz789'
}
};
const gasketRequest = await makeGasketRequest(requestLike);
console.log(gasketRequest.path); // '/api/data'
console.log(gasketRequest.query); // { filter: 'active', sort: 'name' }
Headers Object
import { makeGasketRequest } from '@gasket/request';
// Using Headers Web API
const headers = new Headers();
headers.set('content-type', 'application/json');
headers.set('x-api-key', 'secret123');
const gasketRequest = await makeGasketRequest({
headers,
path: '/api/endpoint',
query: { version: 'v1' }
});
console.log(gasketRequest.headers['content-type']); // 'application/json'
getOriginalRequest
Retrieves the original framework request that a GasketRequest was normalized
from. Use it to reach framework-specific fields that GasketRequest does not
normalize, such as ip.
Returns undefined when there is no original request to return — see
Caveats.
Treat the result as read-only. Do not mutate the request or consume its body: a
fetch Request or IncomingMessage body is a single-use stream, so reading it
here leaves nothing for the handler that reads it next.
Express original request
Express derives req.ip from the trust proxy setting, so it is not something
GasketRequest can normalize. Reach it through the original request:
import express from 'express';
import { getOriginalRequest } from '@gasket/request';
const app = express();
app.set('trust proxy', true);
export default {
name: 'audit-plugin',
hooks: {
// The hook only receives the normalized GasketRequest
async publicGasketData(gasket, data, { req }) {
const original = getOriginalRequest(req);
console.log(original?.ip); // '203.0.113.42'
console.log(req.method); // 'GET' — normalized, no lookup needed
return data;
}
}
};
Fastify original request
Fastify exposes request.ip, and request.ips when trustProxy is enabled:
import Fastify from 'fastify';
import { getOriginalRequest, makeGasketRequest } from '@gasket/request';
const fastify = Fastify({ trustProxy: true });
fastify.get('/users', async (request, reply) => {
const gasketRequest = await makeGasketRequest(request);
// Later, anywhere holding only the GasketRequest
const original = getOriginalRequest(gasketRequest);
console.log(original?.ip); // '203.0.113.42'
console.log(original?.ips); // ['203.0.113.42', '198.51.100.7']
return { ok: true };
});
TypeScript
The return type is generic so you can assert the framework you are in. The assertion is unchecked — you are telling TypeScript what you already know:
import type { Request as ExpressRequest } from 'express';
import type { FastifyRequest } from 'fastify';
import { getOriginalRequest } from '@gasket/request';
const expressReq = getOriginalRequest<ExpressRequest>(req);
const fastifyReq = getOriginalRequest<FastifyRequest>(req);
const ip = expressReq?.ip; // string | undefined
Caveats
getOriginalRequest returns undefined when no original request exists — a
directly constructed GasketRequest, or anything that is not a
GasketRequest.
In the Next.js App Router there is no request instance. @gasket/nextjs
assembles a request-like object from next/headers, so getOriginalRequest
returns a truthy object that has no ip:
// App Router — RSC
const original = getOriginalRequest(req);
console.log(Boolean(original)); // true — the check you reach for does not help
console.log(original.ip); // undefined
Guard the field, not the object:
const ip = getOriginalRequest(req)?.ip;
if (!ip) {
// No client IP available in this environment
}
withGasketRequest
Higher-order function that wraps GasketActions functions to receive a normalized GasketRequest.
Basic Usage
import { withGasketRequest } from '@gasket/request';
// Define an action that works with GasketRequest
const getUserAction = withGasketRequest(
async function handler(gasket, gasketRequest) {
const userId = gasketRequest.query.userId;
const authToken = gasketRequest.headers.authorization;
// Use gasketRequest properties
console.log(`Getting user ${userId} with auth: ${authToken}`);
return { userId, authenticated: !!authToken };
}
);
With Additional Arguments
import { withGasketRequest } from '@gasket/request';
const processDataAction = withGasketRequest(
async function handler(gasket, gasketRequest, dataType, options) {
const locale = gasketRequest.headers['accept-language'];
const userId = gasketRequest.cookies.userId;
console.log(`Processing ${dataType} for user ${userId} in ${locale}`);
return {
dataType,
userId,
locale,
processed: true,
...options
};
}
);
// Usage with additional arguments
const result = await processDataAction(gasket, req, 'analytics', { format: 'json' });
In Plugin Actions
// In a Gasket plugin
export default {
name: 'user-plugin',
actions: {
getCurrentUser: withGasketRequest(
async function getCurrentUser(gasket, gasketRequest) {
const sessionId = gasketRequest.cookies.sessionId;
const userAgent = gasketRequest.headers['user-agent'];
if (!sessionId) {
return null;
}
// Fetch user from database using session
const user = await gasket.actions.findUserBySession(sessionId);
return {
...user,
userAgent,
lastAccess: new Date()
};
}
)
}
};
withGasketRequestCache
Higher-order function that wraps action functions with per-request caching.
Basic Caching
import { withGasketRequestCache } from '@gasket/request';
// Expensive operation that should be cached per request
const getUserPermissions = withGasketRequestCache(
async function handler(gasket, gasketRequest) {
const userId = gasketRequest.cookies.userId;
console.log(`Fetching permissions for user ${userId}`);
// Simulate expensive database call
await new Promise(resolve => setTimeout(resolve, 100));
return {
userId,
permissions: ['read', 'write', 'admin'],
fetchedAt: new Date()
};
}
);
Configuration Caching
import { withGasketRequestCache } from '@gasket/request';
const getFeatureFlags = withGasketRequestCache(
async function handler(gasket, gasketRequest, environment) {
const userId = gasketRequest.cookies.userId;
const region = gasketRequest.headers['cf-ipcountry'];
console.log(`Loading feature flags for user ${userId} in ${region}`);
const flags = await gasket.actions.loadFeatureFlags({
userId,
region,
environment
});
return flags;
}
);
WeakPromiseKeeper
A utility class for managing weakly-referenced promise caches.
Basic Usage
import { WeakPromiseKeeper } from '@gasket/request';
const cache = new WeakPromiseKeeper();
// Use object as key
const requestObj = { id: 'req123' };
// Store a promise
const dataPromise = new Promise(resolve =>
setTimeout(() => resolve({ data: 'value' }), 1000)
);
cache.set(requestObj, dataPromise);
// Check if key exists
console.log(cache.has(requestObj)); // true
// Get the promise/value
const result = await cache.get(requestObj);
console.log(result); // { data: 'value' }
// After promise resolves, get returns the resolved value directly
const cachedResult = cache.get(requestObj); // No await needed
console.log(cachedResult); // { data: 'value' }