0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring for GraphQLでもスキーマと実装に不一致があればSpring Bootの起動を停止したい

Posted at

既に1年近く前の話ですが、愛用していたGraphQL Spring Boot Startersがアーカイブになってしまいました。Spring for GraphQLの登場で予想はしていましたが、まだ機能面で不満があったので残念です。

しかし、時代は待ってくれませんし、Spring for GraphQLでのDataLoaderの実装(特に@BatchMapping)は簡単になりますし、Spring Frameworkなので今後の進歩も期待できるので、移行は大歓迎でもあります。

不満

不満とは、スキーマと実装に不一致があったときの挙動で

  • GraphQL Spring Boot Starters
2024-10-12T12:34:02.149+09:00 ERROR 224838 --- [template-project] [  restartedMain] o.s.boot.SpringApplication               : Application run failed

org.springframework.context.ApplicationContextException: Unable to start web server

...中略...

Caused by: graphql.kickstart.tools.resolver.FieldResolverError: No method or field found as defined in schema <unknown>:14 with any of the following signatures (with or without one of [interface graphql.schema.DataFetchingEnvironment, class graphql.GraphQLContext] as the last argument), in priority order:

  example.domain.AccountModel.address()
  example.domain.AccountModel.getAddress()
  example.domain.AccountModel.address
  • Spring for GraphQL
2024-10-12T12:29:03.484+09:00  INFO 220161 --- [template-project] [           main] o.s.b.a.g.GraphQlAutoConfiguration       : GraphQL schema inspection:
	Unmapped fields: {AccountModel=[address]}
	Unmapped registrations: {}
	Unmapped arguments: {}
	Skipped types: []

GraphQL Spring Boot Startersはエラーが発生してSpring Bootの起動が停止するのに対し、Spring for GraphQLはログに出るものの、そのままSpring Bootは起動してしまいます。そして、当然ながら実行中には実装の不一致に伴うエラーが発生するわけです。

このSpring for GraphQLの挙動は大規模開発とかでは便利なんですかね?巨大なスキーマがあって、複数のアプリケーションで実装を分担するみたいな。

でも自分だとほぼ1人で完結する程度の開発なので、スキーマの一部をワザと実装しないということもないし、実装漏れには確実に気づきたいわけです。

解決策

まずは結論の実装コードから。

@Configuration
class GraphQlConfig {
  @Bean
  @ConditionalOnProperty(prefix = "spring.graphql.schema.inspection", name = ["stop-on-unmapped"], havingValue = "true", matchIfMissing = false)
  fun graphQlSourceBuilderReportConsumerCustomizer(): GraphQlSourceBuilderCustomizer {
    return GraphQlSourceBuilderCustomizer{ builder: GraphQlSource.SchemaResourceBuilder ->
      builder.inspectSchemaMappings { report ->
        check(report.unmappedArguments().isEmpty()
          && report.unmappedFields().isEmpty()
          && report.unmappedRegistrations().isEmpty()
          && report.skippedTypes().isEmpty()) {
          report.toString()
        }
      }
    }
  }
}

Spring for GraphQLの自動設定だと、GraphQlAutoConfiguration#graphQlSourceの中で、GraphQlSource.SchemaResourceBuilder#inspectSchemaMappingsメソッドにログオブジェクトのinfoメソッドを渡しています。これによりGraphQlSource.SchemaResourceBuilder#initGraphQlSchemaの中でSchemaReportが生成され、ログとして出力されていました。

そこで自作のGraphQlSourceBuilderCustomizerにより、
GraphQlSource.SchemaResourceBuilder#inspectSchemaMappingsメソッドに渡すオブジェクトを上書きし、SchemaReportで不一致を検出したら例外を発生させるようにしました。

また、この挙動をプロパティで制御できるようにもしました。

これにより不一致がある場合は以下のような出力でSpring Bootの起動が停止するようになりました。

2024-10-12T13:30:59.211+09:00 ERROR 255549 --- [template-project] [           main] o.s.boot.SpringApplication               : Application run failed

...中略...

Caused by: java.lang.IllegalStateException: GraphQL schema inspection:
	Unmapped fields: {AccountModel=[address]}
	Unmapped registrations: {}
	Unmapped arguments: {}
	Skipped types: []

まとめ

この他にも、Spring for GraphQLへ移行するにあたって、セキュリティやエラー処理など、いろいろと検証していきます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?