The GraphQL worker provides a GraphQL API surfacing the PeeringDB dataset using graphql-yoga. It is driven by the schema extraction pipeline.
Client → wrapHandler (error trap + telemetry headers)
→ extractApiKey / extractSessionId → authenticated
→ isRateLimited (isolate-level, per-IP or per-identity)
→ validateRequest (method checks, URL validation)
→ env.PDB.withSession("first-unconstrained") → db (global connection)
→ Router
→ GET / → GraphiQL UI (handlers/static.js)
→ POST/GET → graphql-yoga pipeline (handlers/query.js)
→ L1 Read + SWR (SHA-256 keyed)
→ yoga.fetch() → Resolver Map → D1
graphql/
├── index.js Router, rate limiter init
├── cache.js LRU cache, TTLs, withGqlSWR(), graphqlCacheKey()
└── handlers/
├── query.js handleGraphQLQuery (yoga pipeline + SWR)
└── static.js serveGraphiQL (custom-branded explorer UI)
Dependencies flow downward: handlers → cache.js → core/.
No cross-worker imports — shared logic lives in core/.
Unlike traditional GraphQL implementations where schemas are authored by hand, this API is generated by scripts/gen_graphql_schema.py.
- Type Definitions (
extracted/graphql-typedefs.js): Emits SDL strings establishing GraphQL object types, Connection configurations (for Relay specification capabilities), and input filter objects. - Resolvers (
extracted/graphql-resolvers.js): An exported map dictating how queries map into the shared API query builder.
- List Queries: Support offset/limit offset pagination (
limit,skip) mapped directly to SQL limits viabuildJsonQuery. - Detail Queries: Fetch a single entity by ID.
- Forward Foreign Keys (Relationships): e.g.
Network.organization. Resolves the parentOrganizationusing the storedorg_id. - Reverse Edge Navigation: e.g.
Network.facilities. Plural endpoints nested inside an entity definition mapped to an implicit Foreign Key filter. - Connections (Relay Pagination): Extends list queries to emit Relay-compliant pagination (
nodes,edges,pageInfo,cursor) leveraging base 64 encoded offsets.
The codebase aims for drop-in compatibility with older downstream client expectations like PeeringDB Plus, generating backward compatible aliases (e.g., querying internetExchanges which maps natively to the ix table). These overrides are defined via the naming meta block inside ENTITY_NAMING in parse_django_models.py.
Entities marked _restricted: true in the entity registry (currently only poc) are restricted by the shared WHERE builder (buildWherePagination in api/query.js), not by the resolvers. Every resolver passes ctx.authenticated through opts.authenticated; for anonymous callers the builder pins visible = 'Public' and ignores any caller-supplied visible filter. The same rule applies to the API and REST workers.
| Resolver | Anonymous Behaviour |
|---|---|
listResolver (e.g. pocs) |
Public contacts only, with or without other filters. |
detailResolver (e.g. poc(id: N)) |
The contact if it is public, else null (matches upstream /api/poc/{id}). |
reverseEdgeResolver (e.g. Network.pointsOfContact) |
Public contacts only, matching the API worker's depth expansion. |
connectionResolver (e.g. pocsConnection) |
Public contacts only, in both totalCount and the page. |
Authenticated callers receive all visibility levels without restriction.
Because GraphQL requests generally employ query bodies over POST, cache keys are formulated by generating a SHA-256 digest of the raw POST string.
- Keys are partitioned by authentication scope prefixed with either
auth:oranon:. - This ensures authenticated queries (which can retrieve private points of contact) never poison the cache for anonymous users attempting the same query body.
- L1 LRU: A 2000-slot LRU cache in
cache.js. Due to the high combinatorial possibility of uniquely shaped GraphQL queries, a GraphQL request retains a ~10% capacity isolation ratio.
withGqlSWR() in cache.js wraps core/swr.js, injecting the GraphQL-specific cache, TTL, and sentinel. The flow matches the API worker pattern: L1 hit → stale-serve + background refresh → miss.
The interactive API shell natively bundled inside Yoga is disabled (graphiql: false), replaced with a custom-branded interface served by handlers/static.js.
The custom page inside frontend/api/graphql.html establishes the interactive API explorer. It bypasses pdbfe.dev Cloudflare Access restrictions by inlining standard CSS and directly importing Inter font assets from the Google Web Fonts CDN.