Skip to content

Field Selection

Grant optimizes database queries by only fetching the fields and relations that clients actually request — reducing I/O, memory, and network bandwidth.

GraphQL

GraphQL resolvers extract requested fields from the info parameter and pass them to the data layer:

typescript
const getUsersResolver: QueryResolvers['users'] = async (_parent, args, context, info) => {
  const requestedFields = info ? getDirectFieldSelection(info, 'User') : undefined;
  return context.providers.users.getUsers({ ...args, requestedFields });
};

The repository builds an optimized SQL query selecting only the requested columns. If no field selection is provided, it falls back to selecting all fields.

REST API — Relations Parameter

REST endpoints use the relations query parameter to load related entities on-demand:

bash
# No relations (default) — base fields only
GET /api/accounts/acc_123

# Single relation
GET /api/accounts/acc_123?relations=projects

# Multiple relations
GET /api/accounts/acc_123?relations=projects,owner

Without relations, only scalar fields are returned. Each relation adds a LEFT JOIN to the query, so request only what you need.

Available Relations

EntityRelations
Accountsprojects, owner
Usersroles, tags, accounts, authenticationMethods
Organizationsusers, projects, roles, groups
Projectsaccounts, users, roles, groups
Rolesusers, groups, tags
Groupsusers, permissions, tags

Performance Impact

ScenarioQuery typeSpeed
No relationsSingle table queryFastest
1-2 relationsLEFT JOIN per relationFast
3+ relationsMultiple LEFT JOINsModerate

GraphQL vs REST Comparison

AspectGraphQLREST
Field selectionAutomatic from query syntax?relations= parameter
Base fieldsMust be explicitly requestedAlways returned
Nested dataDeeply nested queriesFlat relation list
Type safetySchema-drivenZod validation

Adding Relations to New Endpoints

  1. Most list/get schemas already extend listQuerySchema which includes relationsQuerySchema
  2. Parse in the route handler:
typescript
import { parseRelations } from '@/lib/field-selection.lib';

const requestedFields = parseRelations<Entity>(relations);
const result = await handlers.entity.getEntities({ ...params, requestedFields });
  1. Document available relations in the OpenAPI description

Related:

Released under the MIT License.