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 azerrorsmezőben érkeznek. - A
dataéserrorsmező egyszerre is jelen lehet (részleges sikeresség). - A
extensions.codemező segít a kliensoldalon azonosítani a hiba típusát. - A
formatErrormiddleware éles környezetben elrejtheti a belső hibákat. - Input validációhoz érdemes Zod-ot vagy hasonló könyvtárat használni.