Skip to content

Quick Start

This guide walks you through building a simple GraphQL API with queries, mutations, and type-safe arguments.

A basic user API with:

  • A users query that returns a list of users
  • A user(id) query that returns a single user
  • A createUser mutation
  1. Define Your Schema

    Use Effect Schema to define your data types:

    import * as S from "effect/Schema"
    // User schema with validation
    const UserSchema = S.Struct({
    id: S.String,
    name: S.String,
    email: S.String,
    })
    // Input for creating users
    const CreateUserInput = S.Struct({
    name: S.String.pipe(S.minLength(1)),
    email: S.String.pipe(S.pattern(/@/)),
    })
    // TypeScript types are inferred automatically
    type User = S.Schema.Type<typeof UserSchema>
  2. Build the GraphQL Schema

    Use GraphQLSchemaBuilder to create your schema:

    import { Effect } from "effect"
    import { GraphQLSchemaBuilder } from "@effect-gql/core"
    // Sample data
    const users: User[] = [
    { id: "1", name: "Alice", email: "alice@example.com" },
    { id: "2", name: "Bob", email: "bob@example.com" },
    ]
    const schema = GraphQLSchemaBuilder.empty
    // Register the User type
    .objectType({ name: "User", schema: UserSchema })
    // Query: get all users
    .query("users", {
    type: S.Array(UserSchema),
    resolve: () => Effect.succeed(users),
    })
    // Query: get user by ID
    .query("user", {
    type: UserSchema,
    args: S.Struct({ id: S.String }),
    resolve: (args) => {
    const user = users.find(u => u.id === args.id)
    return user
    ? Effect.succeed(user)
    : Effect.fail(new Error("User not found"))
    },
    })
    // Mutation: create a new user
    .mutation("createUser", {
    type: UserSchema,
    args: CreateUserInput,
    resolve: (args) => {
    const newUser: User = {
    id: String(users.length + 1),
    name: args.name,
    email: args.email,
    }
    users.push(newUser)
    return Effect.succeed(newUser)
    },
    })
    // Build the final GraphQL schema
    .buildSchema()
  3. Execute Queries

    Use the execute function to run GraphQL operations:

    import { execute } from "@effect-gql/core"
    import { Layer } from "effect"
    // Execute a query
    const result = await Effect.runPromise(
    execute(schema, Layer.empty)(`
    query {
    users {
    id
    name
    email
    }
    }
    `)
    )
    console.log(JSON.stringify(result, null, 2))

    Output:

    {
    "data": {
    "users": [
    { "id": "1", "name": "Alice", "email": "alice@example.com" },
    { "id": "2", "name": "Bob", "email": "bob@example.com" }
    ]
    }
    }
  4. Run with Arguments

    Pass variables to your queries:

    const result = await Effect.runPromise(
    execute(schema, Layer.empty)(
    `query GetUser($id: String!) {
    user(id: $id) {
    name
    email
    }
    }`,
    { id: "1" } // variables
    )
    )

Here’s the full code in one file:

import { Effect, Layer } from "effect"
import * as S from "effect/Schema"
import { GraphQLSchemaBuilder, execute } from "@effect-gql/core"
// Schema definitions
const UserSchema = S.Struct({
id: S.String,
name: S.String,
email: S.String,
})
type User = S.Schema.Type<typeof UserSchema>
// In-memory data store
const users: User[] = [
{ id: "1", name: "Alice", email: "alice@example.com" },
{ id: "2", name: "Bob", email: "bob@example.com" },
]
// Build schema
const schema = GraphQLSchemaBuilder.empty
.objectType({ name: "User", schema: UserSchema })
.query("users", {
type: S.Array(UserSchema),
resolve: () => Effect.succeed(users),
})
.query("user", {
type: UserSchema,
args: S.Struct({ id: S.String }),
resolve: (args) => {
const user = users.find(u => u.id === args.id)
return user
? Effect.succeed(user)
: Effect.fail(new Error("User not found"))
},
})
.buildSchema()
// Execute
const main = execute(schema, Layer.empty)(`
query {
users { id name email }
}
`)
Effect.runPromise(main).then(console.log)