0Pricing
PHP Academy · Aula

Construindo um esquema com graphql-php

Defina tipos e um esquema com webonyx/graphql-php.

Construindo um esquema com graphql-php é uma aula grátis de PHP Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de PHP Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de PHP Academy inclui 4 aulas no total.

graphql-php: a implementação de referência

webonyx/graphql-php é, na prática, a adaptação para PHP da implementação de referência do GraphQL. Ele fornece o sistema de tipos, o analisador, o validador e o executor. Você define seu esquema de forma programática (objetos PHP) ou a partir de SDL (com o esquema como fonte). Nesta lição, construímos um esquema manualmente para que você entenda exatamente o que cada parte faz.

composer require webonyx/graphql-php

Escalares e o registro de tipos

Todo valor do GraphQL termina em um escalar: Int, Float, String, Boolean, ID. No graphql-php, eles ficam na fachada Type. Como os tipos de objeto fazem referência uns aos outros (e a si mesmos), um padrão comum é um TypeRegistry estático que memoriza cada tipo, para que ele seja construído apenas uma vez.

<?php
use GraphQL\Type\Definition\Type;

// Built-in scalars, returned as singletons:
var_dump(Type::int()->name);     // "Int"
var_dump(Type::string()->name);  // "String"
var_dump(Type::id()->name);      // "ID"
var_dump(Type::nonNull(Type::string())->toString()); // "String!"

Definindo um ObjectType

Um ObjectType tem um name e um mapa de fields. Cada campo declara seu type e, opcionalmente, uma função de retorno resolve. Se você omitir resolve, o graphql-php usará o resolvedor padrão, que lê a chave de matriz ou a propriedade ou método de acesso correspondente no valor pai.

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

$postType = new ObjectType([
    'name' => 'Post',
    'fields' => [
        'id'    => Type::nonNull(Type::id()),
        'title' => Type::nonNull(Type::string()),
        'body'  => Type::string(),
    ],
]);

Empacotamento de não nulo e listas

Os tipos de empacotamento expressam nulidade e cardinalidade:

  • Type::nonNull(T) → T! (nunca nulo).
  • Type::listOf(T) → [T] (uma lista possivelmente nula e possivelmente com membros nulos).
  • [Post!]! = uma lista não nula de posts não nulos → nonNull(listOf(nonNull($postType))).

Acerte isso: esse é o contrato de nulidade do seu esquema com os clientes.

<?php
use GraphQL\Type\Definition\Type;

// [Post!]!  -- a required list whose elements are never null
$wrapped = Type::nonNull(Type::listOf(Type::nonNull(Type::string())));
echo $wrapped->toString(), "\n"; // [String!]!

Campos adiados interrompem referências circulares

Um User tem posts, e um Post tem author (um usuário). Para construir tipos que fazem referência mútua, passe fields como uma função de fechamento em vez de uma matriz. O fechamento é executado de forma adiada, depois que os dois tipos existem, evitando o problema do ovo e da galinha.

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

class Types {
    private static array $cache = [];

    public static function user(): ObjectType {
        return self::$cache['User'] ??= new ObjectType([
            'name' => 'User',
            'fields' => fn() => [           // lazy!
                'id'    => Type::nonNull(Type::id()),
                'name'  => Type::nonNull(Type::string()),
                'posts' => Type::listOf(self::post()),
            ],
        ]);
    }

    public static function post(): ObjectType {
        return self::$cache['Post'] ??= new ObjectType([
            'name' => 'Post',
            'fields' => fn() => [
                'id'     => Type::nonNull(Type::id()),
                'title'  => Type::nonNull(Type::string()),
                'author' => self::user(),    // back-reference
            ],
        ]);
    }
}

Argumentos de campos

Os campos podem receber argumentos. Declare-os na chave args; eles chegam como o segundo parâmetro ($args) do resolvedor. Os argumentos também são tipados, podem ser não nulos e podem conter defaultValue.

<?php
use GraphQL\Type\Definition\Type;

$userField = [
    'type' => Type::string(),
    'args' => [
        'id'     => Type::nonNull(Type::id()),
        'locale' => ['type' => Type::string(), 'defaultValue' => 'en'],
    ],
    'resolve' => fn($root, array $args) => "user {$args['id']} ({$args['locale']})",
];

O tipo raiz de consulta

Todo esquema precisa de um tipo raiz de consulta — os pontos de entrada pelos quais os clientes podem começar. Aqui expomos um único campo hello para podermos executar tudo de ponta a ponta. O primeiro argumento do resolvedor raiz é o rootValue do esquema (frequentemente null).

<?php
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

$queryType = new ObjectType([
    'name' => 'Query',
    'fields' => [
        'hello' => [
            'type' => Type::string(),
            'args' => ['name' => Type::nonNull(Type::string())],
            'resolve' => fn($root, array $args) => 'Hello, ' . $args['name'],
        ],
    ],
]);

Montando e executando o esquema

Envolva o tipo de consulta em um Schema e execute uma string de consulta por meio de GraphQL::executeQuery(). O objeto de resultado é convertido na matriz canônica { data, errors } por meio de toArray().

<?php
require 'vendor/autoload.php';

use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;

$queryType = new ObjectType([
    'name' => 'Query',
    'fields' => [
        'hello' => [
            'type' => Type::string(),
            'args' => ['name' => Type::nonNull(Type::string())],
            'resolve' => fn($root, $args) => 'Hello, ' . $args['name'],
        ],
    ],
]);

$schema = new Schema(['query' => $queryType]);
$result = GraphQL::executeQuery($schema, '{ hello(name: "Ada") }');
echo json_encode($result->toArray());
// {"data":{"hello":"Hello, Ada"}}

Alternativa com o esquema como fonte usando BuildSchema

Se preferir SDL, BuildSchema::build() analisa uma string de esquema e a transforma em um esquema executável. Em seguida, você anexa os resolvedores separadamente (por exemplo, uma função de retorno de campo), mantendo as definições de tipo declarativas enquanto a lógica permanece em PHP.

<?php
use GraphQL\Utils\BuildSchema;

$sdl = <<<'GQL'
type Query {
  hello(name: String!): String
}
GQL;

$schema = BuildSchema::build($sdl);
// Provide resolvers via the executeQuery $fieldResolver argument
// or with a type config decorator.

Valide antes de publicar

O graphql-php valida automaticamente as consultas recebidas em relação ao esquema antes da execução. Você também pode garantir que o próprio esquema seja internamente consistente no momento da compilação/CI com $schema->assertValid() — detecte erros de digitação e referências quebradas antes da implantação, não no momento da requisição.

<?php
use GraphQL\Type\Schema;

/** @var Schema $schema */
$schema->assertValid(); // throws InvariantViolation on a broken schema
echo "schema OK\n";

Enumerações e escalares personalizados

Além dos objetos, dois tipos completam a maioria dos esquemas. EnumType restringe um campo a um conjunto fixo de valores nomeados. CustomScalarType permite definir escalares de domínio (DateTime, e-mail) com sua própria lógica de serialize/parseValue/parseLiteral, para que os valores sejam validados e normalizados na fronteira.

<?php
use GraphQL\Type\Definition\EnumType;

$statusEnum = new EnumType([
    'name' => 'PostStatus',
    'values' => [
        'DRAFT'     => ['value' => 0],
        'PUBLISHED' => ['value' => 1],
        'ARCHIVED'  => ['value' => 2],
    ],
]);
// A field typed as $statusEnum only accepts DRAFT/PUBLISHED/ARCHIVED.

Verificação rápida

Por que passar fields como uma função de fechamento?

Recapitulação

Você construiu um esquema do zero:

  • Escalares e tipos de empacotamento (nonNull, listOf) expressam o contrato de nulidade e cardinalidade.
  • ObjectType com um mapa de campos (ou uma função de fechamento adiada) define suas estruturas.
  • Um registro de tipos que memoriza os tipos lida com referências circulares.
  • Os campos recebem args tipados; o tipo raiz Query é o ponto de entrada.
  • GraphQL::executeQuery() o executa; assertValid() protege o esquema na CI.

A seguir: resolvedores, mutações e assinaturas.

Perguntas Frequentes

A aula “Construindo um esquema com graphql-php” é grátis?

Sim — o texto completo de “Construindo um esquema com graphql-php” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de PHP Academy, atualize para CoddyKit PRO. O curso de PHP Academy inclui 4 aulas no total.

O que vou aprender em “Construindo um esquema com graphql-php”?

Defina tipos e um esquema com webonyx/graphql-php. Você pratica PHP Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar PHP Academy?

Nenhuma experiência prévia é necessária. PHP Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Construindo um esquema com graphql-php”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de PHP Academy?

Sim. Cada aula de PHP Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. GraphQL versus REST
  2. Construindo um esquema com graphql-php
  3. Resolutores, mutações e assinaturas
  4. Desempenho: N+1 e DataLoader
← Voltar para PHP Academy