2
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?

More than 1 year has passed since last update.

GraphQL + Javaでアップロードされたファイルを処理する

Posted at

概要

  • JavaでGraphQLサーバーを構築した際のファイルアップロード処理の実装例
  • GraphQLクライアント側の説明は割愛

構成

  • Java 11
  • SpringBoot 2.3.4
  • gradle 7.4.1
  • GraphQL For Java
    • graphql-spring-boot-starter 7.1.0 ref. 1
    • io.github.kobylynskyi.graphql.codegen 5.5.0

※. 最新のSpringBootの構成ではないため注意!

実装方法

ポイント

  • schema定義について
    • GraphQLのschema定義ではアップロードするファイルをUploadで定義する
    • Uploadは、Java側で任意のクラスにマッピングするため、scalarに記載する
  • Java側について
    • schema定義のUploadをjavax.servlet.http.Partで受け取る

詳細

① 各種設定ファイルを準備

  1. Spring Initializrのベースになるプロジェクトを作成
  2. build.gradleを以下のように記載
    • build.gradle
      plugins {
      	id 'org.springframework.boot' version '2.3.4.RELEASE'
      	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
          id 'io.github.kobylynskyi.graphql.codegen' version '5.5.0'
      	id 'java'
      }
      
      group = 'com.example'
      version = '0.0.1-SNAPSHOT'
      sourceCompatibility = '11'
      
      repositories {
      	mavenCentral()
      }
      
      dependencies {
          implementation 'org.springframework.boot:spring-boot-starter'
      	testImplementation 'org.springframework.boot:spring-boot-starter-test'
          implementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:7.1.0'
          testImplementation 'com.graphql-java-kickstart:graphql-spring-boot-starter:7.1.0'
      }
      
      tasks.named('test') {
      	useJUnitPlatform()
      }
      
  3. URLなどはデフォルト設定のまま利用するので、application.propertiesは変更しなくてOK ref. 2

② ファイルアップロードのschema定義を作成

  1. 以下のようにする ref. 3
    • graphql/schema.graphqls
      """
      アップロードファイル
      """
      scalar Upload
      
      # 今回、Queryは使用しないが、書かないとアプリケーション起動時に怒られるため記載
      type Query {}
      
      type Mutation {
        """ 
        ファイルをアップロードする
        """
        upload(
          """ ファイル """
          file: Upload
        ): Boolean
      }
      

③ schema定義からJavaのインターフェース・クラスを生成する

  1. 手で作成してもよいですが今回はgraphql-java-codegenで生成します。ref. 4
  2. build.gradleに以下のように設定を追加
    • build.gradle
      // 末尾に追記
      // GraphQL schema定義からのJavaコード生成
      apply from: 'gradle/graphql-java-codegen.gradle'
      
  3. 設定ファイルgraphql-java-codegen.gradleを作成し、schema.graphqlsにおいてscalarに定義したUploadをMappingする型などを設定 ref. 3,ref. 5
    • gradle/graphql-java-codegen.gradle
      apply plugin: "io.github.kobylynskyi.graphql.codegen"
      
      compileJava.options.encoding = 'UTF-8'
      
      graphqlCodegen {
          // all config options:
          // https://github.com/kobylynskyi/graphql-java-codegen/blob/master/docs/codegen-options.md
          outputDir = new File("$buildDir/generated")
          graphqlSchemas.includePattern = "schema\\.graphqls"
          apiPackageName = "com.example.demographqlfileupload.graphql.resolvers"
          // 通常、modelが存在しないことはほぼあり得ないが、本サンプルでは存在しないため指定しない
          //modelPackageName = "com.example.demographqlfileupload.graphql.model"
          modelNameSuffix = "TO"
          // scalarのマッピング対象クラス
          customTypesMapping = [
              Upload: "javax.servlet.http.Part"
          ]
          parentInterfaces {
              queryResolver = "graphql.kickstart.tools.GraphQLQueryResolver"
              mutationResolver = "graphql.kickstart.tools.GraphQLMutationResolver"
          }
      }
      
  4. 設定ファイルを元に以下のgradleコマンドを実行しファイルを生成する。
    • gradle graphqlCodegen -Dfile.encoding=utf-8
  5. $buildDir/generated配下にファイルが生成されているのでプロジェクトの任意のフォルダに移動。今回は以下に移動した。
    • /demographqlfileupload/src/main/java/com/example/demographqlfileupload/graphql/resolvers
  6. 以下のようなファイルが生成されるので、プロジェクトにコピー
    • UploadMutationResolver.java
      package com.example.demographqlfileupload.graphql.resolvers;
      
      /**
       * ファイルをアップロードする
       */
      @javax.annotation.processing.Generated(
          value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
          date = "2022-10-25T19:12:40+0900"
      )
      public interface UploadMutationResolver extends graphql.kickstart.tools.GraphQLMutationResolver {
      
          /**
           * ファイルをアップロードする
           */
          Boolean upload(javax.servlet.http.Part file) throws Exception;
      
      }
      

④ scalarからの変換を明示

  1. 以下のようなクラスを作成 ref. 6
    • ExtendedScalarConfiguration.java
      package com.example.demographqlfileupload.config;
      
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      import graphql.kickstart.servlet.apollo.ApolloScalars;
      import graphql.schema.GraphQLScalarType;
      
      @Configuration
      public class ExtendedScalarConfiguration {
      
        @Bean
        public GraphQLScalarType uploadScalar() {
            return ApolloScalars.Upload;
        }
      }
      

⑤ ③で生成したinterfaceを使ってResolverクラスを作成

  1. 以下のようなクラスを作成
    • UploadResolver
      package com.example.demographqlfileupload.resolver;
      
      import javax.servlet.http.Part;
      
      import org.springframework.stereotype.Component;
      
      import com.example.demographqlfileupload.graphql.resolvers.QueryResolver;
      import com.example.demographqlfileupload.graphql.resolvers.UploadMutationResolver;
      
      @Component
      public class UploadResolver
          implements UploadMutationResolver, QueryResolver {
      
      	@Override
      	public Boolean upload(Part file) throws Exception {
            if (Objects.isNull(file)) {
                return false;
            }
      		System.out.println(file.getSubmittedFileName());
      		return null;
      	}
      }
      

⑥ 適宜ちゃんとファイル処理できるようにして完成!

動作確認

  • いろいろGraphQLクライアントはあると思いますが、私はPostmanで統一したいのでPostmanを使っています。
  • ファイルアップロードについては癖があるので注意

Postmanでの手順 ref. 7

  1. GraphQLではなくform-dataを選択
    image.png
  2. KEY/VALUEに以下のように設定
    • operations / {"query":"mutation upload($file: Upload){upload(file: $file)}","variables":{"file":null}}
    • map / {"0":["variables.file"]}
    • 0 / 任意のファイル ※. ここは形式をTextではなくFileに変更
  3. 実行!ファイル情報も取得できているしよさそう
    image.png
    image.png

まとめ

  • GraphQLのschema定義scalarでUploadを指定する
  • Java側ではschema定義のUploadをjavax.servlet.http.Partで受け取れるようマッピングしてやる
  • SpringBootのバージョンによって取得するGraphQLのDependenciesが変わっているので注意!!

その他

  • GraphQLはアップロードはサポートしていますがダウンロードに使うのは想定されていないようです。自前で実装しましょう。
    • Springならコントローラーを追加して通常のHttpRequestとして処理すればOK
  • Spring Boot 2.7 以降はSpring InitializrでSpring for GraphQLというDependenciesを利用することができます。提供されるパッケージが変わるため本稿の実装はそのままは使えないです。
    • 例えば本稿ではgraphql.kickstartのパッケージを利用していますが、バージョンによってはこのパッケージは提供されていないため利用できなくなります。ref. 8, ref. 9, ref. 10

参考情報

引用部

全体的なとこ

2
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
2
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?