Skip to content

Request Middleware

Request Middleware allows you to intercept and modify requests and responses made by the SDK. This can be useful for logging, retries, authentication, metrics collection, custom headers, and other cross-cutting concerns.

Simply put, the middleware is just a function that receives the outgoing request and a next function. The middleware can inspect or modify the request before passing it to the next middleware in the chain.

import { type RequestMiddleware } from '@community-fabs/playfab-sdk/core';
const middleware: RequestMiddleware = async (req, next) => {
// Run logic before the request
const response = await next(req);
// Run logic after the request
return response;
};

Middleware is attached to a PlayFab SDK instance using the .with() method.

import { initializePlayFab } from '@community-fabs/playfab-sdk/core';
const playfab = initializePlayFab({
titleId: 'YOUR_TITLE_ID',
developerSecretKey: 'YOUR_DEV_SECRET_KEY',
}).with(myMiddleware());

Multiple middleware can be chained together.

const playfab = initializePlayFab({
titleId: 'YOUR_TITLE_ID',
})
.with(loggerMiddleware())
.with(retryMiddleware(3))
.with(metricsMiddleware());

Middleware executes in the order it is registered.

A simple logging middleware can help with debugging and development.

import {
initializePlayFab,
type RequestMiddleware,
} from '@community-fabs/playfab-sdk/core';
function loggerMiddleware(): RequestMiddleware {
return async (req, next) => {
console.log('Request:', req);
const res = await next(req);
console.log('Response:', res);
return res;
};
}
const playfab = initializePlayFab({
titleId: 'YOUR_TITLE_ID',
}).with(loggerMiddleware());

Middleware can be used to automatically retry failed requests.

import {
initializePlayFab,
type RequestMiddleware,
} from '@community-fabs/playfab-sdk/core';
function retryMiddleware(retries = 2): RequestMiddleware {
return async (req, next) => {
let lastError: unknown;
for (let i = 0; i <= retries; i++) {
try {
return await next(req);
} catch (err) {
lastError = err;
}
}
throw lastError;
};
}
const playfab = initializePlayFab({
titleId: 'YOUR_TITLE_ID',
}).with(retryMiddleware(3));

Middleware can modify outgoing requests before they are sent.

import { type RequestMiddleware } from '@community-fabs/playfab-sdk/core';
function customHeaderMiddleware(): RequestMiddleware {
return async (req, next) => {
req.headers = {
...req.headers,
'X-Application-Version': '1.0.0',
'X-Environment': 'development',
};
return next(req);
};
}

You can use middleware to collect performance metrics.

import { type RequestMiddleware } from '@community-fabs/playfab-sdk/core';
function metricsMiddleware(): RequestMiddleware {
return async (req, next) => {
const start = performance.now();
try {
return await next(req);
} finally {
const duration = performance.now() - start;
console.log(
`${req.url} completed in ${duration.toFixed(2)}ms`
);
}
};
}

Middleware wraps around subsequent middleware in the chain.

Given:

initializePlayFab({
titleId: 'YOUR_TITLE_ID',
})
.with(middlewareA())
.with(middlewareB())
.with(middlewareC());

Execution order:

middlewareA (before)
middlewareB (before)
middlewareC (before)
API Request
middlewareC (after)
middlewareB (after)
middlewareA (after)

This pattern allows middleware to perform work both before and after a request is executed.

Middleware can be used for things like:

  • Request and response logging
  • Automatic retries
  • Custom authentication
  • Adding request headers
  • Metrics and telemetry collection
  • Error tracking
  • Request timing and profiling
  • Distributed tracing
  • Keep middleware focused on a single responsibility.
  • Avoid mutating request objects unless necessary.
  • Prefer reusable middleware factories that accept configuration.
  • Be cautious when retrying non-idempotent operations.
  • Always rethrow errors unless you intentionally want to handle them.
  • Keep logging and telemetry lightweight in production environments.