Открояване на серия от данни:
- Apollo Server се предлага като пакет Node. Можем да го използваме, за да създадем сървър, който да приема GraphQL заявки.
В тази статия ще разгледаме как да добавяме грешки към сървър Express Apollo.
Обработка на грешки
Apollo Server има колекция от предварително дефинирани грешки, включително AuthenticationError
, ForbiddenError
, UserInputError
и ApolloError
.
Тези грешки правят нашето приложение лесно за отстраняване на грешки, като предоставят информация за нашата грешка.
Например, можем да върнем грешки, както следва:
const express = require('express'); const { ApolloServer, gql, SchemaDirectiveVisitor } = require('apollo-server-express'); const fs = require('fs'); const typeDefs = gql` type Query { readError: String } `; const resolvers = { Query: { readError: (parent, args, context) => { fs.readFileSync('/does/not/exist'); }, }, }; const app = express(); const server = new ApolloServer({ typeDefs, resolvers, }); server.applyMiddleware({ app }); app.listen(3000, () => console.log('server started'));
В кода по-горе се опитваме да прочетем файл, който не съществува в нашия резолвер.
Така че, когато направим заявката:
{ readError }
Ще получим:
{ "errors": [ { "message": "ENOENT: no such file or directory, open '/does/not/exist'", "locations": [ { "line": 2, "column": 3 } ], "path": [ "readError" ], "extensions": { "code": "INTERNAL_SERVER_ERROR", "exception": { "errno": -2, "code": "ENOENT", "syscall": "open", "path": "/does/not/exist", "stacktrace": [ "Error: ENOENT: no such file or directory, open '/does/not/exist'", " at Object.fs.openSync (fs.js:660:18)", " at Object.fs.readFileSync (fs.js:565:33)", " at readError (/home/runner/index.js:14:10)", " at field.resolve (/home/runner/node_modules/graphql-extensions/dist/index.js:133:26)", " at resolveFieldValueOrError (/home/runner/node_modules/graphql/execution/execute.js:467:18)", " at resolveField (/home/runner/node_modules/graphql/execution/execute.js:434:16)", " at executeFields (/home/runner/node_modules/graphql/execution/execute.js:275:18)", " at executeOperation (/home/runner/node_modules/graphql/execution/execute.js:219:122)", " at executeImpl (/home/runner/node_modules/graphql/execution/execute.js:104:14)", " at Object.execute (/home/runner/node_modules/graphql/execution/execute.js:64:35)" ] } } } ], "data": { "readError": null } }
Можем да видим следата на стека къде е проблемът.
Кодове
Експортираните грешки на Apollo Server посочват четим от човека низ в полето code
на extensions
, който позволява на клиента да извършва коригиращи действия.
Също така ни позволява да категоризираме грешките.
Например, ако имаме:
const express = require('express'); const { ApolloServer, gql, AuthenticationError } = require('apollo-server-express'); const typeDefs = gql` type Query { authenticationError: String } `; const resolvers = { Query: { authenticationError: (parent, args, context) => { throw new AuthenticationError('not authenticated'); }, }, }; const app = express(); const server = new ApolloServer({ typeDefs, resolvers, }); server.applyMiddleware({ app }); app.listen(3000, () => console.log('server started'));
Тогава получаваме:
{ "errors": [ { "message": "not authenticated", "locations": [ { "line": 2, "column": 3 } ], "path": [ "authenticationError" ], "extensions": { "code": "UNAUTHENTICATED", "exception": { "stacktrace": [ "AuthenticationError: not authenticated", " at authenticationError (/home/runner/index.js:13:13)", " at field.resolve (/home/runner/node_modules/graphql-extensions/dist/index.js:133:26)", " at resolveFieldValueOrError (/home/runner/node_modules/graphql/execution/execute.js:467:18)", " at resolveField (/home/runner/node_modules/graphql/execution/execute.js:434:16)", " at executeFields (/home/runner/node_modules/graphql/execution/execute.js:275:18)", " at executeOperation (/home/runner/node_modules/graphql/execution/execute.js:219:122)", " at executeImpl (/home/runner/node_modules/graphql/execution/execute.js:104:14)", " at Object.execute (/home/runner/node_modules/graphql/execution/execute.js:64:35)", " at /home/runner/node_modules/apollo-server-core/dist/requestPipeline.js:246:46", " at Generator.next (<anonymous>)" ] } } } ], "data": { "authenticationError": null } }
Виждаме, че получаваме AuthenticationError
, защото можем да видим, че:
"code": "UNAUTHENTICATED"
е в нашата грешка JSON.
Увеличаване на подробностите за грешката
Можем да добавим повече подробности за грешките от предоставените по подразбиране.
Например можем да напишем:
const express = require('express'); const { ApolloServer, UserInputError, gql, } = require('apollo-server-express'); const typeDefs = gql` type Mutation { userInputError(input: String): String } type Query { hello: String } `; const resolvers = { Query: { hello: () => 'Hello' }, Mutation: { userInputError: (parent, args, context, info) => { if (args.input !== 'expected') { throw new UserInputError('Form Arguments invalid', { invalidArgs: Object.keys(args), }); } }, }, }; const app = express(); const server = new ApolloServer({ typeDefs, resolvers, }); server.applyMiddleware({ app }); app.listen(3000, () => console.log('server started'));
В кода по-горе имаме:
throw new UserInputError('Form Arguments invalid', { invalidArgs: Object.keys(args), });
в нашата мутация, за да добавим свойството invalidArgs
към нашия JSON за грешка и стойностите args
, които изпратихме.
Следователно, когато правим заявка, както следва:
mutation { userInputError(input: "foo") }
Получаваме:
{ "errors": [ { "message": "Form Arguments invalid", "locations": [ { "line": 2, "column": 3 } ], "path": [ "userInputError" ], "extensions": { "invalidArgs": [ "input" ], "code": "BAD_USER_INPUT", "exception": { "invalidArgs": [ "input" ], "stacktrace": [ "UserInputError: Form Arguments invalid", " at userInputError (/home/runner/index.js:25:15)", " at field.resolve (/home/runner/node_modules/graphql-extensions/dist/index.js:133:26)", " at resolveFieldValueOrError (/home/runner/node_modules/graphql/execution/execute.js:467:18)", " at resolveField (/home/runner/node_modules/graphql/execution/execute.js:434:16)", " at /home/runner/node_modules/graphql/execution/execute.js:244:18", " at /home/runner/node_modules/graphql/jsutils/promiseReduce.js:23:10", " at Array.reduce (<anonymous>)", " at promiseReduce (/home/runner/node_modules/graphql/jsutils/promiseReduce.js:20:17)", " at executeFieldsSerially (/home/runner/node_modules/graphql/execution/execute.js:241:37)", " at executeOperation (/home/runner/node_modules/graphql/execution/execute.js:219:55)" ] } } } ], "data": { "userInputError": null } }
Частта:
"invalidArgs": [ "input" ]
не е включено по подразбиране, ние го добавихме чрез предаване на втори аргумент към конструктора UserInputError
.
Грешки при пренаписване
Можем да добавим функция rewriteError
, която да връща само някои грешки, така че да се докладват само някои.
Например можем да напишем:
const server = new ApolloServer({ typeDefs, resolvers, engine: { rewriteError(err) { if (err instanceof AuthenticationError) { return null; } return err; } }, });
за да избегнете изпращането на AuthenticationError
s до Apollo Graph Manager.
Можем също така да върнем модифициран обект err
, така че да можем да редактираме някои данни, които не искаме да регистрираме.
Заключение
Apollo Server идва с някои вградени грешки. Можем да ги хвърлим, когато трябва да ги регистрираме в Apollo Graph Manager и да покажем информацията за грешка в отговора.
Можем също така да добавим наши собствени данни към грешките, като ги предадем във втория аргумент на конструкторите.