Skip to content

GraphQL Schema Definition

This guide covers advanced schema definition patterns in api.zig GraphQL.

Overview

GraphQL schemas define the shape of your API. api.zig provides a type-safe schema builder with full support for the GraphQL specification.

Type System

Object Types

Object types are the most common type in GraphQL schemas:

zig
try schema.addObjectType(.{
    .name = "User",
    .description = "A user in the system",
    .fields = &.{
        .{ .name = "id", .type_name = "ID", .is_non_null = true },
        .{ .name = "name", .type_name = "String", .is_non_null = true },
        .{ .name = "email", .type_name = "Email" },
        .{ .name = "role", .type_name = "UserRole", .is_non_null = true },
        .{ .name = "posts", .type_name = "Post", .is_list = true },
        .{ .name = "createdAt", .type_name = "DateTime", .is_non_null = true },
    },
});

Input Types

Input types are used for mutation arguments:

zig
try schema.addInputType("CreateUserInput", &.{
    .{ .name = "name", .type_name = "String", .is_non_null = true },
    .{ .name = "email", .type_name = "Email", .is_non_null = true },
    .{ .name = "role", .type_name = "UserRole", .default_value = "USER" },
}, "Input for creating a user");

Enum Types

Enums define a fixed set of values:

zig
try schema.addEnumType("UserRole", &.{
    .{ .name = "ADMIN", .description = "Full access" },
    .{ .name = "MODERATOR", .description = "Content moderation" },
    .{ .name = "USER", .description = "Standard user" },
    .{ .name = "GUEST", .description = "Read-only", .is_deprecated = true, .deprecation_reason = "Use USER instead" },
}, "User permission levels");

Interface Types

Interfaces define common fields:

zig
try schema.addInterfaceType("Node", &.{
    .{ .name = "id", .type_name = "ID", .is_non_null = true },
}, "Relay Node interface for pagination");

// Implement interface
try schema.addObjectType(.{
    .name = "User",
    .implements = &.{"Node"},
    .fields = &.{
        .{ .name = "id", .type_name = "ID", .is_non_null = true },
        .{ .name = "name", .type_name = "String", .is_non_null = true },
    },
});

Union Types

Unions combine multiple types:

zig
try schema.addUnionType("SearchResult", &.{
    "User", "Post", "Comment", "Tag",
}, "Search can return different types");

Scalar Types

api.zig includes 30+ built-in scalar types:

Standard Scalars

ScalarZig TypeDescription
ID[]const u8Unique identifier
String[]const u8UTF-8 string
Inti3232-bit integer
Floatf6464-bit float
Booleanbooltrue/false

Date/Time Scalars

ScalarFormatExample
DateTimeISO 86012024-01-15T10:30:00Z
DateISO 86012024-01-15
TimeISO 860110:30:00
TimestampUnix1705312200
DurationISO 8601PT1H30M

Validation Scalars

ScalarValidates
EmailRFC 5322 email
URLRFC 3986 URI
UUIDUUID v4
IPv4IPv4 address
IPv6IPv6 address
PhoneE.164 phone
PostalCodePostal code

Numeric Scalars

ScalarRange
BigIntArbitrary precision
DecimalArbitrary precision
PositiveInt> 0
NonNegativeInt>= 0
NegativeInt< 0
PositiveFloat> 0.0

Other Scalars

ScalarDescription
JSONArbitrary JSON
UploadFile upload
BytesBase64 binary
CurrencyISO 4217
VoidNo return

Root Types

Query Type

zig
try schema.setQueryType(.{
    .name = "Query",
    .fields = &.{
        .{ .name = "users", .type_name = "User", .is_list = true, .is_non_null = true },
        .{ .name = "user", .type_name = "User", .args = &.{
            .{ .name = "id", .type_name = "ID", .is_non_null = true },
        }},
    },
});

Mutation Type

zig
try schema.setMutationType(.{
    .name = "Mutation",
    .fields = &.{
        .{ .name = "createUser", .type_name = "User", .args = &.{
            .{ .name = "input", .type_name = "CreateUserInput", .is_non_null = true },
        }},
    },
});

Subscription Type

zig
try schema.setSubscriptionType(.{
    .name = "Subscription",
    .fields = &.{
        .{ .name = "userCreated", .type_name = "User", .is_non_null = true },
    },
});

Field Modifiers

Non-Null Fields

zig
.{ .name = "id", .type_name = "ID", .is_non_null = true }
// GraphQL: id: ID!

List Fields

zig
.{ .name = "posts", .type_name = "Post", .is_list = true }
// GraphQL: posts: [Post]

Non-Null List with Non-Null Items

zig
.{ .name = "tags", .type_name = "String", .is_list = true, .is_non_null = true, .list_item_non_null = true }
// GraphQL: tags: [String!]!

Arguments

Required Arguments

zig
.args = &.{
    .{ .name = "id", .type_name = "ID", .is_non_null = true },
}

Optional Arguments with Defaults

zig
.args = &.{
    .{ .name = "limit", .type_name = "Int", .default_value = "10" },
    .{ .name = "offset", .type_name = "Int", .default_value = "0" },
}

Deprecation

zig
.{
    .name = "oldField",
    .type_name = "String",
    .is_deprecated = true,
    .deprecation_reason = "Use newField instead",
}

SDL Export

Export schema as SDL:

zig
const sdl = try schema.toSDL(allocator);
defer allocator.free(sdl);
std.debug.print("{s}\n", .{sdl});

Output:

graphql
type Query {
  users: [User]!
  user(id: ID!): User
}

type User {
  id: ID!
  name: String!
  email: Email
  role: UserRole!
}

enum UserRole {
  ADMIN
  USER
  GUEST
}

See Also

Released under the MIT License.