Learning
GraphQL

Hibakezelés és validáció

GraphQL hibastruktúra, szerveroldali hibaformázás és input validáció gyakorlati mintákkal.

Hibakezelés és validáció

A GraphQL hibakezelése eltér a REST-től. A REST HTTP státuszkódokat használ (404, 500 stb.), a GraphQL viszont szinte mindig 200 OK-kal válaszol, és a hibákat a válasz törzsében adja vissza.

A GraphQL válasz struktúrája

{
  "data": {
    "user": null
  },
  "errors": [
    {
      "message": "User not found",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["user"],
      "extensions": {
        "code": "NOT_FOUND",
        "statusCode": 404
      }
    }
  ]
}

A data és az errors mező egyszerre is lehet jelen – ez azt jelenti, hogy a lekérdezés részben sikeres volt.

Hibák dobása a resolverben

const { GraphQLError } = require('graphql');

const resolvers = {
  Query: {
    user: async (_, { id }, { db, currentUser }) => {
      // Autentikáció ellenőrzése
      if (!currentUser) {
        throw new GraphQLError('Bejelentkezés szükséges', {
          extensions: {
            code: 'UNAUTHENTICATED',
            statusCode: 401,
          },
        });
      }

      const user = await db.users.findById(id);

      // Nem található
      if (!user) {
        throw new GraphQLError(`Felhasználó nem található: ${id}`, {
          extensions: {
            code: 'NOT_FOUND',
            statusCode: 404,
          },
        });
      }

      // Jogosultság ellenőrzése
      if (user.id !== currentUser.id && currentUser.role !== 'ADMIN') {
        throw new GraphQLError('Nincs jogosultság', {
          extensions: {
            code: 'FORBIDDEN',
            statusCode: 403,
          },
        });
      }

      return user;
    },
  },
};

Hibaformázás (formatError)

Az Apollo Serverben globálisan formázhatod a hibákat – például elrejtheted a belső implementációs részleteket éles környezetben:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  formatError: (formattedError, error) => {
    // Belső hibák elrejtése éles környezetben
    if (process.env.NODE_ENV === 'production') {
      if (!formattedError.extensions?.code) {
        return {
          message: 'Belső szerverhiba',
          extensions: { code: 'INTERNAL_SERVER_ERROR' },
        };
      }
    }

    return formattedError;
  },
});

Input validáció

A séma maga is validál (kötelező mezők, típusok), de üzleti logika validációhoz külön könyvtárat érdemes használni (pl. Zod):

const { z } = require('zod');

const createUserSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.string().email(),
  password: z.string().min(8),
});

const resolvers = {
  Mutation: {
    createUser: async (_, { input }) => {
      // Validáció
      const result = createUserSchema.safeParse(input);

      if (!result.success) {
        throw new GraphQLError('Érvénytelen bemenet', {
          extensions: {
            code: 'VALIDATION_ERROR',
            details: result.error.issues,
          },
        });
      }

      return db.users.create(result.data);
    },
  },
};

Hibakezelés a kliens oldalon (Apollo Client)

const { data, error, loading } = useQuery(GET_USER, {
  variables: { id: userId },
});

if (loading) return <LoadingSpinner />;

if (error) {
  const errorCode = error.graphQLErrors[0]?.extensions?.code;

  if (errorCode === 'UNAUTHENTICATED') {
    return <LoginRedirect />;
  }

  if (errorCode === 'NOT_FOUND') {
    return <NotFoundPage />;
  }

  return <ErrorMessage message={error.message} />;
}

Rövid összefoglaló

  • A GraphQL mindig 200 OK-kal válaszol, a hibák az errors mezőben érkeznek.
  • A data és errors mező egyszerre is jelen lehet (részleges sikeresség).
  • A extensions.code mező segít a kliensoldalon azonosítani a hiba típusát.
  • A formatError middleware éles környezetben elrejtheti a belső hibákat.
  • Input validációhoz érdemes Zod-ot vagy hasonló könyvtárat használni.

On this page