SOLID
Gato GraphQL sigue el enfoque SOLID para la arquitectura del software, proporcionando distintas entidades para abordar distintas responsabilidades, de modo que el código sea mantenible, extensible y comprensible.
Así es como la entidad de usuario ya viene proporcionada por el plugin. El tipo User se proporciona mediante este código:
class UserTypeResolver extends AbstractTypeResolver
{
public function getTypeName(): string
{
return 'User';
}
public function getSchemaTypeDescription(): ?string
{
return $this->translationAPI->__('Representation of a user', "users");
}
public function getID(object $user)
{
return $this->usersAPI->getUserId($user);
}
public function getTypeDataLoaderClass(): string
{
return UserTypeDataLoader::class;
}
}El type resolver no carga los objetos directamente desde la base de datos, sino que delega esta tarea a un objeto TypeDataLoader (en el ejemplo anterior, de la clase UserTypeDataLoader).
Añadir los campos username, email y url al tipo User se hace mediante un objeto FieldResolver con este código:
class UserFieldResolver extends AbstractDBDataFieldResolver
{
public static function getClassesToAttachTo(): array
{
return [
UserTypeResolver::class,
];
}
public static function getFieldNamesToResolve(): array
{
return [
'username',
'email',
'url',
];
}
public function getSchemaFieldDescription(
TypeResolverInterface $typeResolver,
string $fieldName
): ?string {
$descriptions = [
'username' => $this->translationAPI->__("User's username handle", "users"),
'email' => $this->translationAPI->__("User's email", "users"),
'url' => $this->translationAPI->__("URL of the user's profile in the website", "users"),
];
return $descriptions[$fieldName];
}
public function getSchemaFieldType(
TypeResolverInterface $typeResolver,
string $fieldName
): ?string {
$types = [
'username' => SchemaDefinition::TYPE_STRING,
'email' => SchemaDefinition::TYPE_EMAIL,
'url' => SchemaDefinition::TYPE_URL,
];
return $types[$fieldName];
}
public function resolveValue(
TypeResolverInterface $typeResolver,
object $user,
string $fieldName,
array $fieldArgs = []
) {
switch ($fieldName) {
case 'username':
return $this->usersAPI->getUserLogin($user);
case 'email':
return $this->usersAPI->getUserEmail($user);
case 'url':
return $this->usersAPI->getUserURL($user);
}
return null;
}
}Como se puede observar, la definición de un campo para el esquema GraphQL, y su resolución, se ha dividido en multitud de funciones:
getSchemaFieldDescriptiongetSchemaFieldTyperesolveValue
Otras funciones incluyen:
getSchemaFieldArgs: para declarar los argumentos del campo (incluyendo su nombre, descripción, tipo y si son obligatorios o no)isSchemaFieldResponseNonNullable: para indicar si un campo es no anulablegetImplementedInterfaceClasses: para definir los resolvers para las interfaces implementadas por los camposresolveFieldTypeResolverClass: para definir el type resolver cuando el campo es una conexiónresolveFieldMutationResolverClass: para definir el resolver cuando el campo ejecuta mutaciones
Este código es más legible que si toda la funcionalidad se cubriera mediante una única función, o mediante un array de configuración, lo que facilita la implementación y el mantenimiento de los resolvers.