[SpringBoot] RestTemplate でAPI内部からAPIを呼び出す

[SpringBoot] RestTemplate でAPI内部からAPIを呼び出す

こんばんは。七色メガネです。

最近Springを触っているので、その延長で一つ記事を。
今回は、Spring で作成したAPIの内部でさらに外部APIを呼び出すということを行なってみたいと思います。

本記事で作ってみたいのは、次のようなプログラムです。

  • localhost/*** にアクセスすると、呼ばれた先のAPIでさらに公開APIである図書館検索APIを呼び出し、そこで取得された結果を返却する

APIがクライアントライブラリを公開している場合はそれをAPIに組み込めばいいだけですけれども、今回は外部APIのエンドポイントに直接アクセスします。

それをSpring上で実行する上で役に立つのが RestTemplate というライブラリです。

今回はプログラムの性質上RestTemplateのGETメソッドにしか触れませんが、用途別にいくつかのパターンで実装していきたいと思います。

環境など

  • 開発環境:IntelliJ
  • 言語:Kotlin
  • フレームワーク:SpringBoot
  • ビルドツール:Gradle

使用する外部API

図書館検索API カーリル
https://calil.jp/

 

実装

今回の主なプログラム構成は次の通りです。

  • LibraryController
    コントローラクラス。
    今回は3つのエンドポイントをハンドルする。
  • LibraryServiceImpl
    コントローラから呼び出されるサービスの実装クラス。
    外部APIへのアクセス3種と、JSONのパース処理をもつ。

前準備

1. APIキーの取得

外部APIを叩くためにAPIキーを取得しておく必要があります。会員登録と開発者登録を行うだけですので、ここでの説明は省きます。

公式のhowtoを読めば5分程度で難なく済ませられるかと思います。
https://calil.jp/doc/api_ref.html

2. プロジェクトの作成

springイニシャライザーでささっとプロジェクトを作成してしまいましょう。
方法については、以下の記事をご参照ください。

[ Kotlin ] SpringBoot / Gradle / IntelliJ を使って HelloWorld する

3. build.gradle への追記

RestTemplate を使うには、spring-boot-starter-web の導入が必要です。
また今回は外部からのAPIからの戻り値がJSONでありそのパースも行なっているので、jacksonも導入しています。

本記事ではパースまで取り扱いませんが、実際にトレースしてみたい人は下の2つを入れておくといいかもしれません。

build.gradleへの追記内容

実装A. 外部APIにURLベースでリクエストを投げて、対象のデータオブジェクトだけを取得する。

では実装です。まずは最も簡単なパターンからみていきます。
このパターンでは、APIから外部APIを呼び出し、レスポンスのボディ部だけを取り出します。
リクエストヘッダやレスポンスステータスを考慮しないので、一番時間のかからない実装です。

Controller

コントローラは単純で、サービスを一つ呼び出しているだけです。サービスからの返却値は既にJSONからオブジェクト型に変換されたデータなので、あとはこれをフロントに返してやればゴールです。なお今回はフロントへの返し方は問題にしていないので、適当にリターンしています。

Controller (get data as object)

Service

サービスでは3つのことを行なっています。

  1. RestTemplate の生成
  2. url の整形
  3. 外部APIの呼び出し、データの取得、及びデータの返却

url の整形はまあどうでも良いとして、1 と 3 が外部APIとの連携で必要になる操作です。

まずは RestTemplate を引数なしで初期化します。
そして生成されたインスタンスの # getForObject メソッドを使用することで、指定したurlのエンドポイントへリクエストを投げることができます。

この時、メソッドの戻り値は getForObject の第二引数で指定したクラス型になります。APIから返されたJSONを自分でパースすることなく、このメソッドがクラスへの落とし込みまで全てやってくれるのです。

逆に言えば、HTTPステータスなどのレスポンスデータは返ってきません。それらの情報が必要な時には、別メソッドでリクエストを投げることになります。

Service (get data as object)

なお、今回の外部API先はJSONデータを配列で返すように作られています。したがって、第二引数で渡すクラスの型も配列で指定しています。

 

実装B. 外部APIにURLベースでリクエストを投げて、レスポンスエンティティを取得する。

先ほどの実装ではレスポンスのボディのみを取得する便利メソッドを使用していましたが、こちらではレスポンスデータを丸ごと取得します。と言ってもちょっと違うメソッドを使うだけです。

Controller (get as entity)

先ほどはサービスからの戻り値が既にデータクラスに変換されていましたが、今回はレスポンスデータが戻り値になっています。

ですのでレスポンスからボディ(JSON)を取り出し、自前でパースをかけてからフロントへ返却しています。今回はパース処理については触れません。

Controller (get as entity)

Service

今回は RestTemplate の #getForEntity を使用しています。これにより、外部APIからのレスポンスデータを取得することができます。

今回は使用していませんが、レスポンスステータスやレスポンスヘッダーなどが戻り値から取り出せていることがコードからわかるかと思います。

Service (get as entity)

 

実装C. 外部APIにリクエストエンティティを投げて、レスポンスエンティティを取得する。

最後の方法は、先の2つとはリクエストの方法が異なります。
今までは外部APIのエンドポイントのURLをメソッドに渡していただけですが、ここで使用するメソッドではリクエストエンティティを使用することができます。つまり、前2つよりもより詳細なリクエストができるということですね。

コントローラは実装Bとほぼ一緒なので割愛です。
サービスのみ見ていきましょう。

Service (get by entity)

ここでは、RestTemplate のメソッドを呼び出す前にリクエストエンティティを定義し、文字コードを指定しています。

そしてリクエストエンティティを使用して呼び出すメソッドが、 #exchange です。

戻り値はレスポンスエンティティなので、実装Bと一緒です。

Service (get by entity)

取得結果

3種の実装を行いましたが、どれも取得結果は同じです。
今回使用しているAPIは図書館の情報を取得してくるものですので、フロントには図書館の名前と住所が出ています。表示にはこだわっていないので、殺風景ではありますね…。

まとめ

  • Spring でAPI内部から外部APIを呼び出したい時には、RestTemplate ライブラリを使用すると、とても簡単に実装を行うことができる。
  • RestTemplate でGETを行う時には、用途に合わせて3つの使い方が選択できる。
    (1) レスポンスボディだけが必要である -> RestTemplate.getForObject
    (2) レスポンスデータが必要である -> RestTemplate.getForEntity
    (3) リクエストデータを編集したい -> RestTemplate.exchange

今回は使用した外部APIの性質上GETパターンしか試すことができませんでしたが、もちろんRestTemplate はそのほかの HTTPメソッド にも対応しています。

いずれまたどこかの機会に試してみようと思います。

 

以上です。ここまで読んでいただき、ありがとうございました!

 

参考

https://sites.google.com/site/soracane/home/springnitsuite/spring-no-ji-nengnitsuite/08-springga-yong-yisuruwebkuraianto-resttemplate-no-shii-fang

https://terasolunaorg.github.io/guideline/5.1.0.RELEASE/ja/ArchitectureInDetail/RestClient.html#get

Kotlinカテゴリの最新記事