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-phpEscalares 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. ObjectTypecom 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
argstipados; o tipo raizQueryé 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
- GraphQL versus REST
- Construindo um esquema com graphql-php
- Resolutores, mutações e assinaturas
- Desempenho: N+1 e DataLoader