Skip to content

Middleware

Register global middleware with simfinity.use() to inspect arguments, enforce prerequisites, or attach request metadata before a generated operation executes.

javascript
import * as simfinity from '@simtlix/simfinity-js';

simfinity.use(async ({ operation, type, context }, next) => {
  if (operation === 'delete' && context?.user?.role !== 'admin') {
    throw new simfinity.auth.ForbiddenError('Only admins can delete records');
  }

  console.log('Preparing operation', {
    operation,
    type: type?.gqltype.name,
  });
  await next();
});

Register middleware once during application startup. Registrations are global to the loaded Simfinity module and apply to its generated operations.

Execution order

For root reads, the sequence is middleware, query scope, query construction, and database execution. For mutations, middleware runs before the transactional mutation handler.

What next() means

next() advances to the next registered middleware. The database resolver executes after the entire middleware chain returns. Code after await next() still runs before database execution, and omitting next() only skips the remaining middleware. Throw an error to cancel the operation.

Use controllers for before/after persistence hooks. Use your GraphQL server's execution hooks to measure complete request duration. MCP's separate tool middleware wraps actual tool execution and has a different contract.

Middleware context

javascript
simfinity.use(async (params, next) => {
  const { args, operation, context } = params;
  // Mutate args or context in place when preparing the operation.
  await next();
});
PropertyAvailability
argsGraphQL arguments: for example, args.input for add/update or args.id for delete.
operationOne of the operation values below.
contextThe GraphQL request context.
typeRegistered type metadata for generated entity operations; absent for custom mutations.
entryCustom mutation name when operation is custom_mutation.
actionName, actionFieldState-machine action name and configuration for state_changed.
OperationTrigger
findList query.
get_by_idSingle-record query.
aggregateAggregation query.
saveGenerated add mutation.
updateGenerated update mutation.
deleteGenerated delete mutation.
state_changedGenerated state-machine action.
custom_mutationRegistered custom mutation.

Prepare arguments

This middleware supplies default pagination for list queries that omit it:

javascript
simfinity.use(async ({ operation, args }, next) => {
  if (operation === 'find' && !args.pagination) {
    args.pagination = { page: 1, size: 25 };
  }
  await next();
});

Mutate the existing args object. Replacing params.args is not a reliable way to replace the resolver's arguments, because the resolver retains its own reference.

For record visibility, prefer the type's query scope. Global middleware does not run for automatic nested relationship resolution or direct programmatic data access.

Open source. Released under the Apache 2.0 License.