Creación de un esquema con graphql-php
Defina tipos y un esquema con webonyx/graphql-php
Creación de un esquema con graphql-php es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.
graphql-php: la implementación de referencia
webonyx/graphql-php es el port de facto para PHP de la implementación de referencia de GraphQL. Le proporciona el sistema de tipos, el analizador, el validador y el ejecutor. Puede definir el esquema programáticamente (mediante objetos PHP) o a partir de SDL (schema-first). En esta lección crearemos un esquema manualmente para que entienda exactamente qué hace cada pieza.
composer require webonyx/graphql-phpEscalares y el registro de tipos
Todo valor de GraphQL termina siendo un escalar: Int, Float, String, Boolean, ID. En graphql-php, estos tipos están disponibles en la fachada Type. Como los tipos de objeto se referencian entre sí (e incluso a sí mismos), un patrón habitual es usar un TypeRegistry estático que memoriza cada tipo para construirlo una sola 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!"
Definir un ObjectType
Un ObjectType tiene un name y un mapa de fields. Cada campo declara su type y, opcionalmente, una función resolve. Si omite resolve, graphql-php utiliza el resolver predeterminado, que lee la clave correspondiente del array o la propiedad/método getter del valor padre.
<?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(),
],
]);
Envoltura Non-Null y de listas
Los tipos envolventes expresan la nulabilidad y la cardinalidad:
Type::nonNull(T)→T!(nunca es null).Type::listOf(T)→[T](una lista que puede ser null y cuyos miembros también pueden ser null).[Post!]!= una lista no nula de posts no nulos →nonNull(listOf(nonNull($postType))).
Defínalo correctamente: es el contrato de nulabilidad de su esquema con los 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!]!
Los campos diferidos rompen las referencias circulares
Un User tiene posts, y un Post tiene un author (un User). Para construir tipos que se referencian mutuamente, pase fields como un closure en lugar de un array. El closure se ejecuta de forma diferida, cuando ambos tipos ya existen, y evita el problema del huevo y la gallina.
<?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 los campos
Los campos pueden aceptar argumentos. Declárelos bajo la clave args; llegan como segundo parámetro ($args) del resolver. Los argumentos también tienen tipos, pueden ser no nulos y pueden incluir 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']})",
];
El tipo raíz Query
Todo esquema necesita un tipo raíz Query: los puntos de entrada desde los que pueden comenzar los clientes. Aquí exponemos un único campo hello para poder ejecutar el flujo completo. El primer argumento del resolver raíz es el rootValue del esquema (a menudo 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'],
],
],
]);
Ensamblar y ejecutar el esquema
Envuelva el tipo de consulta en un Schema y ejecute una cadena de consulta mediante GraphQL::executeQuery(). El objeto de resultado se convierte en el array canónico { data, errors } mediante 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 schema-first con BuildSchema
Si prefiere SDL, BuildSchema::build() analiza una cadena de esquema y la convierte en un esquema ejecutable. Después, conecte los resolvers por separado (por ejemplo, mediante una función de resolución field-resolver), manteniendo declarativas las definiciones de tipos mientras la lógica permanece en 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
graphql-php valida automáticamente las consultas entrantes contra el esquema antes de ejecutarlas. También puede verificar que el esquema sea internamente coherente durante la compilación o en CI mediante $schema->assertValid(): detecte errores tipográficos y referencias rotas antes del despliegue, no en el momento de procesar la solicitud.
<?php
use GraphQL\Type\Schema;
/** @var Schema $schema */
$schema->assertValid(); // throws InvariantViolation on a broken schema
echo "schema OK\n";
Enums y escalares personalizados
Además de los objetos, hay dos tipos que completan la mayoría de los esquemas. EnumType restringe un campo a un conjunto fijo de valores con nombre. CustomScalarType permite definir escalares de dominio (DateTime, Email) con su propia lógica de serialize/parseValue/parseLiteral, de modo que los valores se validan y normalizan en el límite.
<?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.
Comprobación rápida
¿Por qué se pasa fields como un closure?
Resumen
Ha creado un esquema desde cero:
- Los escalares y los tipos envolventes (
nonNull,listOf) expresan el contrato de nulabilidad y cardinalidad. ObjectTypecon un mapa de campos (o un closure diferido) define sus estructuras.- Un registro de tipos con memoización gestiona las referencias circulares.
- Los campos aceptan
argstipados; el tipo raízQueryes el punto de entrada. GraphQL::executeQuery()lo ejecuta;assertValid()protege el esquema en CI.
Siguiente paso: resolvers, mutaciones y suscripciones.
Preguntas frecuentes
¿La lección «Creación de un esquema con graphql-php» es gratis?
Sí — el texto completo de «Creación de un esquema con graphql-php» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Creación de un esquema con graphql-php»?
Defina tipos y un esquema con webonyx/graphql-php Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar PHP Academy?
No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Creación de un esquema con graphql-php»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de PHP Academy?
Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- GraphQL frente a REST
- Creación de un esquema con graphql-php
- Resolvers, mutaciones y suscripciones
- Rendimiento: N+1 y DataLoader