GraphQL

Configuration & Customization

Extra configuration options can be set on SQL entities using comment directives.

Extra configuration options can be set on SQL entities using comment directives.

Comment Directives

Comment directives are snippets of configuration associated with SQL entities that alter how those entities behave.

The format of a comment directive is


_10
@graphql(<JSON>)

Inflection

Inflection describes how SQL entities' names are transformed into GraphQL type and field names. By default, inflection is disabled and SQL names are literally interpolated such that


_10
create table "BlogPost"(
_10
id int primary key,
_10
...
_10
);

results in GraphQL type names like


_10
BlogPost
_10
BlogPostEdge
_10
BlogPostConnection
_10
...

Since snake case is a common casing structure for SQL types, pg_graphql support basic inflection from snake_case to PascalCase for type names, and snake_case to camelCase for field names to match Javascript conventions.

The inflection directive can be applied at the schema level with:


_10
comment on schema <schema_name> is e'@graphql({"inflect_names": true})';

for example


_10
comment on schema public is e'@graphql({"inflect_names": true})';
_10
_10
create table blog_post(
_10
id int primary key,
_10
...
_10
);

similarly would generated the GraphQL type names


_10
BlogPost
_10
BlogPostEdge
_10
BlogPostConnection
_10
...

For more fine grained adjustments to reflected names, see renaming.

Max Rows

The default page size for collections is 30 entries. To adjust the number of entries on each page, set a max_rows directive on the relevant schema entity.

For example, to increase the max rows per page for each table in the public schema:


_10
comment on schema public is e'@graphql({"max_rows": 100})';

totalCount

totalCount is an opt-in field that extends a table's Connection type. It provides a count of the rows that match the query's filters, and ignores pagination arguments.


_10
type BlogPostConnection {
_10
edges: [BlogPostEdge!]!
_10
pageInfo: PageInfo!
_10
_10
"""The total number of records matching the `filter` criteria"""
_10
totalCount: Int! # this field
_10
}

to enable totalCount for a table, use the directive


_10
comment on table "BlogPost" is e'@graphql({"totalCount": {"enabled": true}})';

for example


_10
create table "BlogPost"(
_10
id serial primary key,
_10
email varchar(255) not null
_10
);
_10
comment on table "BlogPost" is e'@graphql({"totalCount": {"enabled": true}})';

Renaming

Table's Type

Use the "name" JSON key to override a table's type name.


_10
create table account(
_10
id serial primary key
_10
);
_10
_10
comment on table public.account is
_10
e'@graphql({"name": "AccountHolder"})';

results in:


_10
type AccountHolder { # previously: "Account"
_10
id: Int!
_10
}

Column's Field Name

Use the "name" JSON key to override a column's field name.


_10
create table public."Account"(
_10
id serial primary key,
_10
email text
_10
);
_10
_10
comment on column "Account".email is
_10
e'@graphql({"name": "emailAddress"})';

results in:


_10
type Account {
_10
nodeId: ID!
_10
id: Int!
_10
emailAddress: String! # previously "email"
_10
}

Computed Field

Use the "name" JSON key to override a computed field's name.


_18
create table "Account"(
_18
id serial primary key,
_18
"firstName" varchar(255) not null,
_18
"lastName" varchar(255) not null
_18
);
_18
_18
-- Extend with function
_18
create function public."_fullName"(rec public."Account")
_18
returns text
_18
immutable
_18
strict
_18
language sql
_18
as $$
_18
select format('%s %s', rec."firstName", rec."lastName")
_18
$$;
_18
_18
comment on function public._full_name is
_18
e'@graphql({"name": "displayName"})';

results in:


_10
type Account {
_10
nodeId: ID!
_10
id: Int!
_10
firstName: String!
_10
lastName: String!
_10
displayName: String # previously "fullName"
_10
}

Relationship's Field

Use the "local_name" and "foreign_name" JSON keys to override a a relationships inbound and outbound field names.


_14
create table "Account"(
_14
id serial primary key
_14
);
_14
_14
create table "Post"(
_14
id serial primary key,
_14
"accountId" integer not null references "Account"(id),
_14
title text not null,
_14
body text
_14
);
_14
_14
comment on constraint post_owner_id_fkey
_14
on "Post"
_14
is E'@graphql({"foreign_name": "author", "local_name": "posts"})';

results in:


_20
type Post {
_20
nodeId: ID!
_20
id: Int!
_20
accountId: Int!
_20
title: String!
_20
body: String!
_20
author: Account # was "account"
_20
}
_20
_20
type Account {
_20
id: Int!
_20
posts( # was "postCollection"
_20
after: Cursor,
_20
before: Cursor,
_20
filter: PostFilter,
_20
first: Int,
_20
last: Int,
_20
orderBy: [PostOrderBy!]
_20
): PostConnection
_20
}

Description

Tables, Columns, and Functions accept a description directive to populate user defined descriptions in the GraphQL schema.


_10
create table "Account"(
_10
id serial primary key
_10
);
_10
_10
comment on table public.account
_10
is e'@graphql({"description": "A User Account"})';
_10
_10
comment on column public.account.id
_10
is e'@graphql({"description": "The primary key identifier"})';


_10
"""A User Account"""
_10
type Account implements Node {
_10
_10
"""The primary key identifier"""
_10
id: Int!
_10
}

Enum Variant

If a variant of a Postgres enum does not conform to GraphQL naming conventions, introspection returns an error:

For example:


_10
create type "Algorithm" as enum ('aead-ietf');

causes the error:


_10
{
_10
"errors": [
_10
{
_10
"message": "Names must only contain [_a-zA-Z0-9] but \"aead-ietf\" does not.",
_10
}
_10
]
_10
}

To resolve this problem, rename the invalid SQL enum variant to a GraphQL compatible name:


_10
alter type "Algorithm" rename value 'aead-ietf' to 'AEAD_IETF';

or, add a comment directive to remap the enum variant in the GraphQL API


_10
comment on type "Algorithm" is '@graphql({"mappings": {"aead-ietf": "AEAD_IETF"}})';

Which both result in the GraphQL enum:


_10
enum Algorithm {
_10
AEAD_IETF
_10
}