SOLID
Gato GraphQL segue a abordagem SOLID para a arquitetura de software, fornecendo diferentes entidades para lidar com diferentes responsabilidades, de modo a tornar o código manutenível, extensível e compreensível.
É assim que a entidade de usuário já é fornecida pelo plugin. O tipo User é fornecido por meio de 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;
}
}O type resolver não carrega diretamente os objetos do banco de dados, mas delega essa tarefa a um objeto TypeDataLoader (no exemplo acima, da classe UserTypeDataLoader).
A adição dos campos username, email e url ao tipo User é feita por meio de um objeto FieldResolver com 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 pode observar, a definição de um campo para o schema GraphQL, e sua resolução, foi dividida em uma série de funções:
getSchemaFieldDescriptiongetSchemaFieldTyperesolveValue
Outras funções incluem:
getSchemaFieldArgs: para declarar os argumentos do campo (incluindo nome, descrição, tipo e se são obrigatórios ou não)isSchemaFieldResponseNonNullable: para indicar se um campo é não nullablegetImplementedInterfaceClasses: para definir os resolvers para as interfaces implementadas pelos camposresolveFieldTypeResolverClass: para definir o type resolver quando o campo é uma conexãoresolveFieldMutationResolverClass: para definir o resolver quando o campo executa mutations
Este código é mais legível do que quando toda a funcionalidade é satisfeita por meio de uma única função, ou por meio de um array de configuração, tornando assim mais fácil implementar e manter os resolvers.