Skip to content
Content
Skill

/graphql-api

Adding custom GraphQL queries and mutations using GraphQLSchemaFactory. Use this skill when the developer wants to add custom GraphQL endpoints, create custom queries or mutations, add business logic to the API layer, build custom resolvers, inject backend services (identity,

BOOST
From plugin
webiny-js
8k76 skills3 MCP
Install
$ npx -y skills add webiny/webiny-js --skill graphql-api --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/graphql-api

Context preview

The summary Claude sees to decide when to auto-load this skill.

Adding custom GraphQL queries and mutations using GraphQLSchemaFactory. Use this skill when the developer wants to add custom GraphQL endpoints, create custom queries or mutations, add business logic to the API layer, build custom resolvers, inject backend services (identity,

SKILL.md

graphql-api.SKILL.md
name: webiny-custom-graphql-api
context: webiny-extensions
description: >
  Adding custom GraphQL queries and mutations using GraphQLSchemaFactory.
  Use this skill when the developer wants to add custom GraphQL endpoints, create custom
  queries or mutations, add business logic to the API layer, build custom resolvers,
  inject backend services (identity, tenancy, CMS use-cases) into their GraphQL schema,
  or build dynamic GraphQL inputs from CMS models. Covers the full pattern from simple
  queries to complex resolvers with dependency injection and permission transformers.

Custom GraphQL API

TL;DR

Add custom GraphQL queries and mutations using `GraphQLSchemaFactory`. Implement `GraphQLSchemaFactory.Interface`, use the schema builder to add type definitions and resolvers (with per-resolver DI), and export with `GraphQLSchemaFactory.createImplementation()`. Register as `<Api.Extension>`.

**YOU MUST include the full file path with the `.ts` extension in every `src` prop.** For example, use `src={"/extensions/MySchema.ts"}`, NOT `src={"/extensions/MySchema"}`. Omitting the file extension will cause a build failure.

**YOU MUST use `export default` for the `createImplementation()` call** when the file is targeted directly by an Extension `src` prop. Using a named export (`export const Foo = SomeFactory.createImplementation(...)`) will cause a build failure. Named exports are only valid inside files registered via `createFeature`.

The GraphQLSchemaFactory Pattern

The `execute` method receives a schema builder and returns it after adding type defs and resolvers.

// extensions/mySchema/MyGraphQLSchema.ts
import { GraphQLSchemaFactory } from "webiny/api/graphql";

class MySchema implements GraphQLSchemaFactory.Interface {
  async execute(
    builder: GraphQLSchemaFactory.SchemaBuilder
  ): Promise<GraphQLSchemaFactory.SchemaBuilder> {
    builder.addTypeDefs(/* GraphQL */ `
      extend type Query {
        hello: String!
      }
    `);

    builder.addResolver({
      path: "Query.hello",
      resolver: () => {
        return () => "Hello, World!";
      }
    });

    return builder;
  }
}

export default GraphQLSchemaFactory.createImplementation({
  implementation: MySchema,
  dependencies: []
});

Register as an extension:

// extensions/mySchema/Extension.tsx
import React from "react";
import { Api } from "webiny/extensions";

export const MySchema = () => {
  return <Api.Extension src={"@/extensions/mySchema/MyGraphQLSchema.ts"} />;
};

Schema Builder API Reference

| Method | Description | | --------------------------------------- | --------------------------------------------------------------------------------------------- | | `builder.addTypeDefs(typeDefs: string)` | Add GraphQL type definitions (use `extend type Query/Mutation` to add to existing root types) | | `builder.addResolver<TArgs>(config)` | Add a resolver with optional per-resolver DI dependencies |

`addResolver` Config

builder.addResolver<TArgs>({
    path: "TypeName.fieldName",         // dot-separated path
    dependencies: [SomeAbstraction],    // optional: DI tokens resolved at request time
    resolver: (dep1, dep2, ...) => {    // factory: receives resolved deps
        return ({ parent, args, context, info }) => {
            // actual resolver logic
            return result;
        };
    }
});

Key points:

  • **`path`**: Dot-separated GraphQL type path, e.g. `"Query.hello"`, `"Mutation.createOrder"`, `"OrderMutation.create"`
  • **`dependencies`**: Array of DI abstraction tokens. Resolved **per-request** from `context.container`, not at schema build time
  • **`resolver`**: A factory function that receives resolved dependencies and returns the actual resolver function
  • **Resolver params**: The inner function receives `{ parent, args, context, info }` (named object, not positional)

Per-Resolver Dependency Injection

Dependencies in `addResolver` are resolved at request time from the request-scoped container. This is different from class-level constructor DI — it gives each resolver access to request-scoped services like identity and tenant context.

import { GraphQLSchemaFactory } from "webiny/api/graphql";
import { IdentityContext } from "webiny/api/security";

class WhoAmISchema implements GraphQLSchemaFactory.Interface {
  async execute(
    builder: GraphQLSchemaFactory.SchemaBuilder
  ): Promise<GraphQLSchemaFactory.SchemaBuilder> {
    builder.addTypeDefs(/* GraphQL */ `
      extend type Query {
        whoAmI: String
      }
    `);

    builder.addResolver({
      path: "Query.whoAmI",
      dependencies: [IdentityContext],
      resolver: (identityContext: IdentityContext.Interface) => {
        return () => {
          const identity = identityContext.getIdentity();
          return `Hello, ${identity.displayName}!`;
        };
      }
    });

    return builder;
  }
}

export default GraphQLSchemaFactory.createImplementation({
  implementation: WhoAmISchema,
  dependencies: []
});

Note: `GraphQLSchemaFactory` implementations typically have `dependencies: []` because DI happens at the resolver level via `addResolver({ dependencies })`, not at the class constructor level.

---

Query Schema with UseCase DI

Full pattern using `Response` / `ErrorResponse` wrappers and UseCase injection:

import { Response } from "@webiny/api-graphql";
import { ErrorResponse } from "@webiny/api-graphql";
import { GraphQLSchemaFactory } from "@webiny/api-graphql/graphql/abstractions.js";
import { GetCurrentEntityUseCase } from "../features/getCurrentEntity/abstractions.js";

class GetCurrentEntitySchema implements GraphQLSchemaFactory.Interface {
  async execute(
    builder: GraphQLSchemaFactory.SchemaBuilder
  ): Promise<GraphQLSchemaFactory.SchemaBui
Read more
Ships withwebiny-js

Open-source content platform. Self-hosted on AWS serverless. Built as a TypeScript framework you extend with code, not a closed product you configure through a UI. Runs on Lambda, DynamoDB, S3, and CloudFront inside your own AWS account. Scales automatically.

Get the whole plugin
Stats
8,048
Stars
682
Forks
Active
Maintenance
TypeScript
Language
2h ago
Last commit
8y ago
Created
9h ago
Added

Repo: webiny/webiny-js

Other skills on webiny-js.