はじめに

こんにちは。西日本テクノロジー&イノベーション室の樋尻です。

私の所属する西日本テクノロジー&イノベーション室では、2020年9月末に「SPA + REST API構成のサービス開発リファレンス(以下サービス開発リファレンス)」を公開しました。こちらは、シングルページアプリケーション(以下SPA)とREST APIから構成されるWebアプリケーションを開発する際に活用して頂けるコンテンツになっています。

前回のブログでは、自前で作成したフロントエンドとサービス開発リファレンスで作成したバックエンドをつないで、フロントエンドとバックエンドを疎結合にできる点をご紹介しました。

今回はそれとは反対に、バックエンドを「Spring」を使って実装し、サービス開発リファレンスで作成したフロントエンドとつないでみます。

  1. サービス開発リファレンスを使ってWebアプリケーションを作成してみよう<導入編>
  2. サービス開発リファレンスを使って1画面作成してみよう
  3. サービス開発リファレンスを使ってREST APIを1つ作成してみよう
  4. サービス開発リファレンスを使ってバリデーションしてみよう
  5. サービス開発リファレンスを使ってファイルダウンロードを実装してみよう
  6. サービス開発リファレンスを使ってCSRF対策をしてみよう
  7. サービス開発リファレンスの方式設計ガイドを使ってみよう
  8. バックエンドはサービス開発リファレンスを使って、フロントエンドは自前で作成してみた
  9. フロントエンドはサービス開発リファレンスを使って、バックエンドは自前で作成してみた(←今回の記事)

    事前準備

    1~6までの記事でご紹介した作業の完成状態をベースに作成しますので、こちらの作業がまだの方は実施してみてください。

    バックエンド

    プロジェクトの作成

    バックエンドのフレームワークには「Spring」を使用します。

    Springではプロジェクトの雛形を作成するためのSpring Initializrが提供されているため、これでバックエンドのプロジェクトを作成します。

    ここでは以下の画面にある設定で作成しました。

    作成するとZIPファイルのダウンロードが始まりますので、ダウンロードが完了したら解凍します。

    解凍すると、プロジェクトの雛形になるフォルダが入っています。そのフォルダの名前を「backend-spring」に変更し、frontendbackendと同じフォルダ階層に配置してください。

    プロジェクトの配置が完了しましたら、backend-springディレクトリで以下のコマンドを実行し、バックエンドを起動してみましょう。

    $ mvn spring-boot:run

    起動が完了したら、以下のURLにアクセスしてみましょう。以下のようなログイン画面が表示されていれば成功です。

    http://localhost:8080/

    確認が完了したらCtrl+Cでバックエンドを停止し、Todo画面を動かすために実装していきます。

    ポート番号とコンテキストパスを変更

    まずは、前回のブログまでに使用していたバックエンドのポート番号とREST APIのパスに合わせるため、ポート番号とコンテキストパスを変更します。

    backend-spring/src/main/resources/application.propertiesファイルに、以下のプロパティを追加します。

    server.port=9080
    server.servlet.context-path=/api

    REST APIの実装

    続いて、Todo画面で使用するREST APIを実装します。

    backend-spring/src/main/javacom.example.controllerパッケージを作成し、以下のTodosControllerクラスを作成します。

    package com.example.controller;
    
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;
    
    @RestController
    @RequestMapping("/todos")
    public class TodosController {
    
        @GetMapping
        public List<TodoResponse> get() {
            // 疎通の検証が目的のため、固定で返却する
            return List.of(
                    new TodoResponse(1L, "やること1"),
                    new TodoResponse(2L, "やること2"),
                    new TodoResponse(3L, "やること3"));
        }
    
        @PostMapping
        public TodoResponse post(@RequestBody PostRequest requestBody) {
            // 疎通を検証が目的のため、入力値の検証はせず、IDは固定で返却する
            return new TodoResponse(4L, requestBody.text);
        }
    
        public static class PostRequest {
    
            public String text;
        }
    
        public static class TodoResponse {
    
            public final Long id;
    
            public final String text;
    
            public TodoResponse(Long id, String text) {
                this.id = id;
                this.text = text;
            }
        }
    }

    前回のブログまでに使用していたバックエンドではDBに接続していましたが、今回はつなぐことを確認するだけの簡易な実装としています。

    CORSの実装

    SPA + REST API構成ではフロントエンドとバックエンドが異なるオリジンになるため、通信するためにはオリジン間リソース共有(以下CORS)を使用する必要があります。

    サービス開発リファレンスでは最初からCORSの設定がされている状態でしたので、ここではSpring Securityで同様のCORS設定を実装します。 backend-spring/src/main/javacom.exampleパッケージに、以下のWebSecurityConfigクラスを作成します。

    package com.example;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.CorsConfigurationSource;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    
    import java.util.List;
    
    import static org.springframework.security.config.Customizer.withDefaults;
    
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors(withDefaults());
        }
    
        @Bean
        CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(List.of("http://localhost:3000"));
            configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH"));
            configuration.setAllowedHeaders(List.of("Content-Type", "X-CSRF-TOKEN"));
            configuration.setAllowCredentials(true);
    
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
    
            return source;
        }
    }

    CSRF対策の実装

    前回のブログまでに使用していたバックエンドではCSRF対策を実装していましたので、ここではSpring Securityで同様のCSRF対策を実装します。

    CSRFトークンの検証はSpring Securityが内部で行ってくれるため、CSRFトークンを取得するためのREST APIを実装します。 backend-spring/src/main/javacom.example.controllerパッケージに、以下のCsrfControllerクラスを作成します。

    package com.example.controller;
    
    import org.springframework.security.web.csrf.CsrfToken;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class CsrfController {
    
        @GetMapping("/csrf_token")
        public CsrfToken csrf(CsrfToken token) {
            return token;
        }
    }

    Spring Securityのデフォルト設定ではCSRFトークンがセッションに保持されていますので、それをそのまま返しています。 ここで注意する点があり、前回のブログまでに使用していたバックエンドで作成したREST APIとは戻り値の型が異なるため、フロントエンドに返却するJSONの項目名も異なります。そのためフロントエンド側で項目名を合わせるための修正が必要になりますので、後ほどご紹介します。

    起動と動作確認

    ここまで実装できたら、backend-springディレクトリで次のコマンドを実行してバックエンドを起動します。

    $ mvn spring-boot:run

    起動が完了したら、以下のURLにアクセスしてみましょう。CSRFトークン取得結果のJSONが表示されていれば、動作確認は完了です。

    http://localhost:8080/api/csrf_token

    フロントエンド

    CSRFトークン取得時の項目名を変更

    バックエンドの実装時にも触れましたとおり、CSRFトークン取得結果であるJSONの項目名が変わっているため、CSRFトークンの取得処理を修正します。

    frontend/src/example/backend/BackendService.tsファイルにあるrefreshCsrfToken関数を、以下のとおり修正します。

    function refreshCsrfToken(): Promise<void> {
      Logger.debug('call service of refreshCsrfToken');
    
      return getCsrfToken().then(({ headerName, token}) => {
        Logger.debug('headerName:', headerName, 'token:', token);
        restClient.csrfTokenHeaderName = headerName;
        restClient.csrfTokenValue = token;
      });
    }

    起動と動作確認

    修正が終わりましたら、frontendディレクトリで次のコマンドを実行し、フロントエンドを起動してみましょう。

    自動でブラウザが立ち上がり、Top画面が表示されます。

    以下のURLでTodo画面を開いて、Todoが表示されることやTodoを登録できることを確認します。

    http://localhost:3000/todo

    確認が完了しましたら、今回の実装については全て完了です。

    まとめ

    このように、Nablarch以外のフレームワークを使用したバックエンドと、サービス開発リファレンスを使用したフロントエンドをつなぐことができました。前回のブログと合わせて、SPA + REST API構成ではフロントエンドとバックエンドが疎結合になるという点についてご紹介しました。

    これまで9回の連載でサービス開発リファレンスの基本的な利用方法をご紹介してきました。これまでご紹介した内容がサービス開発リファレンスをご活用頂くためのお役に立てば幸いです。


    本コンテンツはクリエイティブコモンズ(Creative Commons) 4.0 の「表示—継承」に準拠しています。