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.