GraphQLではエラーになった場合でも http status 200にしてGraphQLのレスポンスをエラーにして、エラーメッセージを返すのが一般的にである。 ただ、それだと特定のエラーの場合のみフロントエンド側でハンドリングしたい時に不便だなと感じていた。
そこで調べた所、GraphQLでは、extensionsを使用してエラーの情報を返すのが正しいようなので、そちらを実装してみた。
PR
backend
アプリ
実装
extensionsは以下を参考に実装した。
実装は、extensionsに定義したエラーコードを返すようにして、frontend側でハンドリングする方式で対応する。まずは、backend側から実装。 エラーコードの定義追加。
■ usecase/custom_error/code.go
package custom_error const ( CodeDefault = "-1" // バリデーションエラー CodeValidation = "000001" // 無効な認証 CodeInvalidAuthorization = "000002" // Not Found CodeNotFound = "000003" // Already Exists CodeAlreadyExists = "000004" // 自身の招待コード CodeMyInviteCode = "000005" )
エラーコードを設定するメソッドを追加。
■usecase/custom_error/error.go
type RequestError struct { Code string Message string } func (re RequestError) Error() string { return re.Message } func NewRequestError(code string, message string) error { return RequestError{Code: code, Message: message} }
上記でエラーコードの設定まで完了したので、GraphQLのエラーハンドリングにextensionsの情報を追加。
■ app.go
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: resolver})) srv.SetErrorPresenter(func(ctx context.Context, e error) *gqlerror.Error { err := graphql.DefaultErrorPresenter(ctx, e) goc := graphql.GetOperationContext(ctx) errorCode := ce.CodeDefault var re ce.RequestError if errors.As(e, &re) { errorCode = re.Code } err.Extensions = map[string]interface{}{ "code": errorCode, } return err })
上記を追加してエラーになるRequestを送信すると、画像のようにextensionsにエラーコードの情報が追加される。
これでbackend側の対応は完了したので、次はfrontend側の対応を行う。
まずは、frontend側でも同様にエラーコードを定義。
const CodeDefault = '-1' as const; // バリデーションエラー const CodeValidation = '000001' as const; // 無効な認証 const CodeInvalidAuthorization = '000002' as const; // Not Found const CodeNotFound = '000003' as const; // Already Exists const CodeAlreadyExists = '000004' as const; // 自身の招待コード const CodeMyInviteCode = '000005' as const; export const errorCode = { CodeDefault, CodeValidation, CodeInvalidAuthorization, CodeNotFound, CodeAlreadyExists, CodeMyInviteCode, };
GraphQLのエラーハンドリングに、extensionsからエラーコードを取得する処理を追加。
const errorLink = onError((error) => { if ((error.graphQLErrors || []).length > 0) { const graphQLErrors = error.graphQLErrors || [ { message: 'エラー発生しました', extensions: { code: errorCode.CodeDefault }, }, ]; const code = graphQLErrors[0]?.extensions?.code ?? errorCode.CodeDefault;
上記でエラーコードの取得まで完了したので、それに合わせてエラー表示の部分を改修。
これでエラーコード毎の判定が行えるようになった。