Fermer

juillet 26, 2024

Introduction à TypeGraphQL

Introduction à TypeGraphQL


GraphQL a changé la façon dont les développeurs interagissent avec les données, mais gérer sa complexité dans Node.js peut être pénible, en particulier avec TypeScript. Explorons TypeGraphQL, un framework qui vise à simplifier la création d’API GraphQL dans un paramètre Node.js et TypeScript.

Dans le paysage moderne du développement Web, la conception d’API est devenue la pierre angulaire de l’architecture des applications. Si GraphQL a révolutionné la façon dont les développeurs interagissent avec les données, gérer leur complexité dans un environnement Node.js peut parfois s’avérer fastidieux, notamment lors de l’utilisation de TypeScript. C’est ici que TypeGraphQL entre en jeu, un framework qui vise à simplifier la création d’API GraphQL dans un cadre Node.js.

Dans cet article, nous approfondirons les principes fondamentaux de TypeGraphQL, en illustrant ses avantages et son utilisation.

Vous souhaitez mieux comprendre ce qu’est GraphQL et en quoi il diffère des API REST traditionnelles ? Consultez cet article que nous avons déjà écrit : GraphQL vs REST : quel est le meilleur choix pour la conception d’API ?

TypeGraphQL

TypeGraphQL est une bibliothèque conçue pour créer des API GraphQL en TypeScript plus efficace. Pour ce faire, il exploite les décorateurs et les classes TypeScript pour définir succinctement les schémas et les résolveurs, permettant ainsi aux développeurs d’écrire du code plus propre et plus évolutif.

Dans un article précédent, nous avons écrit sur Résolveurs GraphQL, nous avons passé en revue un exemple simple de récupération de données utilisateur basées sur un identifiant. Dans cette configuration traditionnelle, le schéma GraphQL (SDL) et les résolveurs ressemblaient à ceci :

Schéma:

type Query {
  user(id: ID!): User
}

type User {
  name: String!
  email: String!
}

Résolveur :

const resolvers = {
  Query: {
    user: (obj, args, context, info) => {
      
      return database.getUserById(args.id);
    },
  },
};

Ce qui précède présente un schéma et un résolveur pour une requête utilisateur. Dans le schéma, un Query le type permet de récupérer un User objet par ID, qui comprend name et email des champs. Le résolveur mappe cette requête à une fonction qui récupère les données utilisateur d’une base de données à l’aide de l’ID fourni, reliant ainsi le schéma GraphQL à la base de données.

Voyons comment cette approche traditionnelle se traduit par un framework TypeGraphQL, améliorant la sécurité des types et réduisant le passe-partout.

Schéma et résolveur TypeGraphQL

Tout d’abord, nous définissons les types GraphQL à l’aide des classes TypeScript et des décorateurs fournis par TypeGraphQL, comme ObjectType, Field et ID:

import { ObjectType, Field, ID } from "type-graphql";

@ObjectType()
class User {
  @Field((type) => ID)
  id: string;

  @Field()
  name: string;

  @Field()
  email: string;
}

Dans l’exemple ci-dessus, nous définissons le type d’objet GraphQL pour un User en utilisant des classes TypeScript, ce qui améliore la sécurité et la maintenabilité des types. Chaque champ du User l’objet est défini avec un @Field décorateur, qui décrit le type de données (telles que ID, String, etc.) et s’il est nullable ou non. Cette approche intègre le schéma GraphQL directement dans l’environnement TypeScript, de sorte que les types de données utilisés sont cohérents dans l’API.

Ensuite, nous définissons la classe de résolution qui gérera la récupération des données utilisateur. Nous utiliserons le @Resolver décorateur de TypeGraphQL pour lier notre classe au type GraphQL spécifié, qui dans ce cas est User:

import { Resolver, Query, Arg } from "type-graphql";
import { User } from "./User";

@Resolver((of) => User)
class UserResolver {
  @Query((returns) => User, { nullable: true })
  async user(@Arg("id") id: string): Promise<User | undefined> {
    
    return await database.getUserById(id);
  }
}

Dans l’exemple ci-dessus, nous implémentons une classe de résolution pour gérer les requêtes de récupération des données utilisateur. Le @Resolver decorator indique que cette classe résoudra les champs pour le User taper. Le @Query decorator est utilisé pour définir une opération de requête dans l’API GraphQL. Le user la fonction prend un id argument marqué du @Arg décorateur et renvoie un User objet ou undefined si aucun utilisateur n’est trouvé avec cet identifiant. Cette configuration simplifie non seulement le code, mais garantit également que chaque composant de l’API est fortement typé et adhère aux définitions du schéma.

Pour construire le schéma, nous pouvons utiliser le buildSchema() fonction fournie par TypeGraphQL.

import { buildSchema } from "type-graphql";
import { UserResolver } from "./UserResolver";

async function createSchema() {
  return await buildSchema({
    resolvers: [UserResolver],
  });
}

Dans l’exemple ci-dessus, buildSchema() est configuré avec UserResolver, intégrant toute la logique que nous avons définie précédemment et crée un schéma exécutable à partir de nos définitions de type et de résolveur. Enfin, nous devrons exécuter la fonction async :

import { buildSchema } from "type-graphql";
import { UserResolver } from "./UserResolver";

async function createSchema() {
  return await buildSchema({
    resolvers: [UserResolver],
  });
}

createSchema();

Une fois le schéma construit, le point de terminaison GraphQL peut être créé et servi à l’aide d’outils tels que Serveur Apollo ou graphql-yoga, montrant comment TypeGraphQL facilite l’intégration de TypeScript avec GraphQL. Le passage de la configuration traditionnelle de GraphQL à TypeGraphQL introduit une approche plus structurée et évolutive pour créer des API GraphQL, exploitant toute la puissance du système de typage statique de TypeScript.

Ce qui précède ne fait qu’effleurer la surface de ce qui peut être fait avec TypeGraphQL, et il y a beaucoup plus à explorer. Ci-dessous, nous passerons en revue une fonctionnalité principale que TypeGraphQL prend bien en charge : l’autorisation.

Autorisation

Dans TypeGraphQL, le @Autorisé decorator est utilisé pour implémenter des contrôles d’autorisation directement dans les définitions de schéma. Cette fonctionnalité puissante nous permet de spécifier quels rôles peuvent accéder à des champs spécifiques ou exécuter des requêtes et des mutations.

Développons le précédent User Par exemple, pour inclure des contrôles d’autorisation indiquant que seuls les utilisateurs autorisés peuvent accéder à certains détails de l’utilisateur. Tout d’abord, nous allons modifier le UserResolver pour inclure les méthodes protégées par le @Authorized décorateur, en précisant quels rôles sont autorisés à y accéder.

import { Resolver, Query, Arg, Mutation, Authorized } from "type-graphql";
import { User, UserInput } from "./User";

@Resolver((of) => User)
class UserResolver {
  
  @Query((returns) => User, { nullable: true })
  async user(@Arg("id") id: string): Promise<User | undefined> {
    return await database.getUserById(id);
  }

  
  @Authorized("ADMIN")
  @Query((returns) => [User])
  async allUsers(): Promise<User[]> {
    return await database.getAllUsers();
  }

  
  @Authorized()
  @Mutation((returns) => User)
  async updateUser(@Arg("userData") userData: UserInput): Promise<User> {
    return await userService.update(userData);
  }
}

Dans l’exemple de code ci-dessus, nous avons amélioré le UserResolver en intégrant un contrôle d’accès basé sur les rôles. Les requêtes et les mutations sont protégées à l’aide du @Authorized décorateur, spécifiant les exigences du rôle directement dans la définition du schéma GraphQL. Cette configuration restreint l’accès en fonction des rôles d’utilisateur, de sorte que seuls les utilisateurs dûment autorisés peuvent effectuer certaines actions, telles que récupérer tous les utilisateurs ou mettre à jour les détails de l’utilisateur.

Ensuite, nous devons créer une fonction de vérification d’authentification, la fonction qui définit la logique pour vérifier si les rôles de l’utilisateur actuel correspondent aux rôles requis par le @Authorized décorateur.

import { AuthChecker } from "type-graphql";
import { Context } from "./Context";

export const customAuthChecker: AuthChecker<MyContext> = (
  { context },
  roles
) => {
  
  if (!context.user) return false;

  
  if (!roles.length) return true;

  
  return roles.some((role) => context.user.roles.includes(role));
};

L’exemple de fonction de vérification d’authentification ci-dessus vérifie :

  1. Si un utilisateur est présent dans le contexte.
  2. Si aucun rôle n’est spécifié, il autorise l’accès à tout utilisateur authentifié.
  3. Si des rôles spécifiques sont spécifiés, il vérifie si l’utilisateur possède l’un de ces rôles.

Enfin, nous devrons intégrer cette fonction de vérification d’authentification lorsque nous créerons notre schéma GraphQL avec TypeGraphQL. Cette étape implique l’enregistrement de la fonction de vérification d’authentification personnalisée auprès du schéma.

import { buildSchema } from "type-graphql";
import { UserResolver } from "./UserResolver";
import { customAuthChecker } from "./auth/custom-auth-checker";

async function createSchema() {
  return await buildSchema({
    resolvers: [UserResolver],
    authChecker: customAuthChecker,
  });
}

En suivant les étapes, nous aurions intégré avec succès l’autorisation basée sur les rôles dans notre API TypeGraphQL. Cette configuration sécurise non seulement notre API, mais fait également en sorte que seuls les utilisateurs autorisés puissent accéder aux opérations et aux données sensibles.

Conclure

Dans cet article, nous avons présenté certains des concepts fondamentaux de ce que TypeGraphQL a à offrir. Au-delà des bases de la définition des schémas et des résolveurs, TypeGraphQL est doté de fonctionnalités telles que injection de dépendance, validation, héritage et intergiciel, qui améliorent ses capacités. De plus, TypeGraphQL prend en charge des fonctionnalités GraphQL plus avancées telles que énumérations, abonnements et directives.

L’intégration de ces fonctionnalités par TypeGraphQL dans l’écosystème TypeScript permet aux développeurs de produire efficacement des API sécurisées, évolutives et maintenables. Pour plus de détails, n’oubliez pas de consulter le documentation officielle de TypeGraphQL!




Source link