100分de名著 カール・マルクス『資本論』 2021年12月 読者メモ

人類へ与えた影響の大きさは最大級の名著、「資本論」です。資本主義は構造的な欠陥を抱えている、それを克服するためには、まず資本主義とは何なのかを明らかにしなければならない。そういった考えで書かれた本です。

今回の解説を担当した斉藤幸平さんは、マルクス研究界で最高峰の賞であるドイッチャー記念賞を史上最年少、日本人で受賞した気鋭の研究者です。

現在、マルクス・エンゲルス全集、通称MEGA(メガ)の刊行が進行中です。編纂過程でマルクスがどのようなことに関心を持っていたのかが新たに明らかになり、これまでとは異なった視点でマルクスが再評価されています。

この本では特に、マルクスが環境問題に対してどのような考えを持っていたのかについて焦点を当てています。

www.amazon.co.jp

本の前半は一般的な資本論の解説で、商品、使用価値と価値、搾取についてなどについて触れています。

資本主義は世界の全てのものを商品として扱い、ここの商品には共通の尺度である価値を付ける。この価値はそのものが持つ使用価値とは関係が無い。

労働者は1日の労働で日給以上の価値を生み出しているため、生み出した価値と日給の差額分だけ資本家に搾取されている。

などなど、この辺は新規の発見はありませんでした。

構想と実行の分離

この本の中で最も面白いと思いました。労働の工程を、構想と実行の二つに分けて考えます。構想は労働者の中から選抜した現場監督に任せ、実行はその他の労働者を厳格に管理しながら行わせます。

本の中では土鍋の製造を例にして説明されていました。資本主義以前では土鍋を作ろうとすると、土鍋職人に一任しなければなりません。どのような土鍋を作るのか、製造法はどうするのか、どのくらいの時間をかけるのか、資本家が決めることはできません。

一方、資本主義では土鍋のデザイン、納期を資本家が決定します。現場監督が製造工程を細かく分け、各労働者は土鍋製造のごく一部のみを延々と担当し続けます。

資本主義のやり方では大量製造が可能で、納期やクオリティもコントロールしやすいです。その代償として、土鍋を作ることのできる労働者はいなくなってしまいます。このようにして、労働者の誇りとやり甲斐が失われ、代替可能な存在となっていきます。これは構想を担当している現場監督でも同じです。

環境問題

おそらくこの本で最も大事な論点だったと思うのですが、個人的には消化不良に感じました。

資本主義世界で人類が自然から搾取している、つまり環境を破壊している事をマルクスが問題視しているのはよく分かりました。しかし、マルクスがこの問題をどう解決しようとしていたのかが読み取れませんでした。ここは、今後MEGAの刊行が進むのを待つべきところかもしれません。

  • 自然に対しても所有者と価値を決めてしまい、共通資産(コモンズ)が失われてしまうこと

  • ゴミを海外で埋め立てるなどして国内の環境問題を解消(外部化)しているが地球は有限であること

などを問題としており、資本主義でいう価値以外の尺度のその代案や既に進んでいる取り組みも紹介されています。我々の中に環境を守りたいという思いがあるのは確かですが、一方で富への欲求や自己顕示欲も強力です。それらと、どのように折り合いをつけていくべきだとマルクスが考えていたのか、今後の研究の進展に期待したいところです。

The Intelligence Trap(インテリジェンス・トラップ) なぜ、賢い人ほど愚かな決断を下すのか 読書メモ

ダニエル・カーネマンの「ファスト&スロー」を読んで以来、行動経済学に関心を持っています。この本も同じ領域を扱っているため、読んでみることにしました。

www.amazon.co.jp

この本では、高いIQや専門知識を持っている人でも誤った決断をしてしまうことがあると主張しています。さらに言えば、このように賢いと見なされる人の方が、平凡な人よりも判断ミスを犯す可能性が高くなってしまうことを示す研究結果を紹介しています。

知性と判断ミスの可能性が比例してしまうこのような現象を、この本では「インテリジェンストラップ」と呼んでいます。

第1部 知能の落とし穴

インテリジェンストラップを支持する研究結果と、ノーベル賞化学者が非科学的な主張に傾倒したこと、高い専門性を持ったプロフェッショナルが愚かな判断をしてしまった事例など具体的なエピソードが提示されています。

第2部 賢いあなたが気をつけること

どのような点に気をつけていれば、インテリジェンストラップを軽減できるのかをまとめています。「主張に対立する意見を探してみる」「断定的な表現を使わない」などなど、罠にかかりにくくなるためのTipsが紹介されていました。

常に懐疑的であって、好奇心を活発にし続けることが大切だと分かります。

第3部 実りある学習法

個人的にここが一番おもしろかったです。

一般的に、下記のような学び方をすれば上達が早いと思われています。

  • 一つの事に集中する

  • まとまった時間を確保する

  • 集中できる書斎を用意する

  • 理解しやすい教材を活用する

しかし、これらは全て誤りであるということが示されています。効率よく上達するためには、「ある程度たくさんの事を、細切れの時間で、さまざまな場所で」学ぶのが適しています。

人は忘れたことを思い出すのは大変です。そのため、頑張って思い出したことは記憶に残りやすいことが分かっています。多くの事を学んでいると、切り替えのたびに前回の続きを思い出さなければならないため、結果として記憶が定着しやすいです。

「細切れの時間で、さまざまな場所で」も同じ理由で、思い出す回数、頑張り具合を増やす効果があります。時間が細切れの方が、前回の続きを思い出す回数が多くなります。また、記憶を呼び出す際に勉強していた場所が鍵になることがあるので、色々な場所で勉強している方がヒントが少なく頑張って思い出すことになります。

第4部 知性ある組織の作り方

サッカー弱小国アイスランドが、一流選手を集めたイングランドを破ったケースや、アメリカの大学生アイスホッケーチームが強豪ソ連チームを破った「氷上の奇跡」など印象深いエピソードをもとに、スター選手ばかりを集めても最強チームは作れないことを示しています。

チームの中のスター選手の割合が多くなると地位争いが発生して、チームのパフォーマンスは低下します。この現象は「逆U字の法則」と呼ばれています。チームの中にスター選手が数人いるとパフォーマンスは上がりますが、その割合が増えていって60%程度になってくると、逆にチームは苦戦しやすくなります。

これを防ぐ方法として、「特定のメンバーだけではなく、全てのメンバーに発言の時間を取る」、「リーダーが謙虚な態度でメンバーに接し、雑用のような仕事でもこなす」などが紹介されていましたが、まだまだ研究途上の分野だとしていました。

組織がメンバーにものを考えさせないようにする「機能的愚鈍」という現象についての研究も紹介されています。要員は様々ですが、特に「組織に対する完全な忠誠心を求め、ポジティブである事を過度に重要視する空気」が機能的愚鈍を生み出すと言われています。「進行中のプロジェクトを批判すると、本気でそれに取り組んでいない証拠とみなされる」ような状態で、組織の自己批判機能が失われています。

加えて、「早く、たくさん、前のめりに失敗する」事をよしとするスタートアップ文化も、機能的愚鈍になりうると指摘されています。失敗を認めて改善していく柔軟な姿勢の表れてある場合は美徳ですが、「失敗の原因を分析しない」、「原因を外部要因(世の中が私のアイデアに追いついていなかった)に求める」場合がままあり、その場合は機能的愚鈍であるとしています。

これには、原子力空母や潜水艦で活用されている工夫が参考になるとしていて、「組織外部のアドバイスを受け入れる」、「自主的に失敗を報告したメンバーを表彰する」、「ルーチンワークの手順を定期的に入れ替える」などの対策が紹介されています。

所感

懐疑的な姿勢や好奇心が認知バイアスを軽減させる、という研究結果は面白くて直感にも合っていますが、そのような態度はどのようにすれば身に付けられるのかは今後の課題だと感じました。自分の知っている範囲内で素早く思考するのが、必ずしも間違っているとも思えないので、みんなが身につけるべき態度かどうかも含めてまだ分からないところです。

学習法に関する部分は常識を覆される結果で、早速自分自身も取り入れ始めています。一つの事に集中するのが苦手なタイプなので、お墨付きをもらえて気持ちが楽になりました。

機能的愚鈍の対策はいくつか挙がっていましたが、まだ今後の発展待ちです。人が関わる問題なのでこれにも一般解はないと思いますが、もっと研究結果が出揃ってくれば機能的愚鈍を軽減することができるのかもしれません。

Fundamentals of Software Architecture: An Engineering Approach 読書メモ

ソフトウェアアーキテクトという仕事についての入門書です。ソフトウェアアーキテクトはまだ歴史の浅い職業なので、体系だった入門書が多くはありません。この本では、アーキテクトが身に付けるべき知識、スキルを

に大別して、それぞれ解説しています。

アーキテクチャ特徴

Architecture characteristicsのことです。邦訳はこれといったものが見当たらなかったので、直訳して使うことにします。

各種アーキテクチャへの要求のうち、個々のソフトウェア固有ではない一般的なもの、のような定義でしょうか。もっとハマりのいい定義があるかもしれません。

アーキテクチャ特徴は沢山あるのですが、この本では下記リストの特徴について、各アーキテクチャスタイルを採点しています。

  • Partitioning type

  • Number of quanta

  • Deployability

  • Elasticity

  • Evolutionary

  • Fault tolerance

  • Modularity

  • Overall cost

  • Performance

  • Reliability

  • Scalability

  • Simplicity

  • Testability

見ていただければ分かりますように、このリストはアーキテクチャ特徴を網羅している訳ではなく、意味が重複している項目もあります。それでも分析の出発点には十分なります。

詳細な定義は原著を読んでもらうのがいいですが、それぞれ簡単に紹介します。

Partitioning type

何を元にコンポーネントを切り分けるか、です。TechnicalDomainの二種類あります。

プレゼンテーション層、サービス層など技術的な関心を元にして切り分ける場合はTechnicalで、ユーザーや商品など、ドメインを元にして切り分ける場合はDomainです。

原著にわかりやすい画像を載せてくれていたので、転載します。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_0804.png Chapter 8. Component-Based Thinking

Number of quanta

デプロイの単位がいくつあるか、です。例えばフロントエンドとバックエンドを分離していて別々にデプロイできる場合、Number of quantaは2となります。

Deployability

デプロイのしやすさです。小さな単位でデプロイできたり、自動化が進んでいる場合は高くなります。逆に、コンポーネントが密結合になっていたり、デプロイ手順に手動の項目が多かったりすると低くなります。

Elasticity

アクセスが急上昇しても耐えられるか、です。Scalabilityとの違いがよく分かっていなかったのですが、

  • Scalability → アクセスが徐々に増えていっても対応できるか

  • Elasticity → アクセスの急な増減に対応できるか

と説明してあって分かりやすかったです。

こちらも原著のイラストで、

Scalability https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_0501.png

Elasticity https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_0502.png

こうして見ると違いがよく分かります。

Evolutionary

新たなコンポーネント、機能を追加するのが容易かを表します。拡張性ですね。

Fault tolerance

一部のコンポーネントが異常でも、システム全体としては正常に動作する能力です。耐障害性が近い?

Modularity

アーキテクチャが、どの程度パーツ毎に分離されているかを表します。モノリシックなアーキテクチャに近付くほど、Modularityは低くなります。

Overall cost

そのアーキテクチャを採用するコストです。サーバーなどの計算リソースだけではなく、実装するエンジニアの作業量や、学習コストなども入ります。そのアーキテクチャに関する経験の薄い組織の場合、アーキテクチャ採用の許可をマネジメント層から得るための説得にかかる労力なども、コスト計算に入れなければならないかもしれません。

Performance

どれだけ多くのリクエストを捌けるか、レスポンスを返すまでにどの程度の時間がかかるのか、などです。

Reliability

信頼性。どれだけ長い時間、システムダウンせずに稼働し続けられるかを表します。

Scalability

継続的なアクセス増加にどの程度対応可能かを表します。Elasicityの項目と比較すると違いがわかりやすいです。

Simplicity

アーキテクチャの単純さを表します。単純なほど理解、実装が容易です。

Testability

テストのしやすさです。細かい粒度でモジュール分けしてある方がテストがしやすく、テスト自動化もしやすいです。

アーキテクチャスタイル

プログラミングにおけるデザインパターンと同じように、アーキテクチャにも定番のパターンが存在します。新たに誕生したり、使われなくなるものもあるので普遍的なものではありませんが、この本では下記のアーキテクチャパターンを取り上げています。

モノリシックアーキテクチャ

  • Layered Architecture Style

  • Pipeline Architecture Style

  • Microkernel Architecture Style

分散アーキテクチャ

  • Service-Based Architecture Style

  • Event-Driven Architecture Style

  • Space-Based Architecture Style

  • Orchestration-Driven Service-Oriented Architecture

  • Microservices Architecture

詳細に解説すると分量が多くなるので、要点のみ簡潔に記載します。

Layered Architecture Style

プレゼンテーション層やサービス層など、層ごとに役割を割り当てて切り分けるアーキテクチャです。

層をスキップしたアクセスはしないのが基本です。↓のイメージだとPresentation LayerはBusiness Layerのみにアクセスできて、Persistence Layer以下へのアクセスはできません。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1001.png

しかし何らかの事情でスキップしたい場合もあります。その場合、スキップが可能な層をopen、スキップできない層をcloseと呼びます。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1005.png

シンプルで分かりやすいのが最大の特徴で、特にプロジェクトの初期に土台として選択するのに適したアーキテクチャです。

Pipeline Architecture Style

独立したFunction同士を繋いでいくアーキテクチャです。シェルのワンライナーなどが代表的です。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1101.png

シンプルさが特徴で、機能の追加なども容易です。パイプラインの途中で異常が発生するとシステム全体が正常に動作しなくなってしまうので、耐障害性は低いです。

Microkernel Architecture Style

コアとなるコンポーネントを用意しておいて、必要に応じて機能をPlug-inするアーキテクチャです。WordPressとかがイメージ近いのかな?と思っています。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1201.png

機能の追加、削除が容易なのが特徴です。

Service-Based Architecture Style

独立したサービスがいくつか(4 ~ 12程度)存在していて、UIとDBを共有しているアーキテクチャです。UIとDBはサービス毎に分離することもあります。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1301.png

非常にバランスが良く柔軟なアーキテクチャなので、分散アーキテクチャの基本として使うことができます。

Event-Driven Architecture Style

特定の条件でイベントを発生させて、各サービスは必要に応じてそのイベントに反応するアーキテクチャです。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1401.png

イベントを中央で管理するMediator Topologyと、

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1405.png

中央管理をしないBroker Topologyが存在します。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1402.png

Mediator Topologyではワークフローやトランザクションの管理がやりやすいですが、複雑さが増すことになります。

機能の追加がしやすく、パフォーマンスも高いですが、どうしても複雑になります。

Space-Based Architecture Style

スケールアウトを試みる際、webサーバー、アプリケーションサーバー、DBの順に難しくなります。DBのボトルネックを解消するために使われるのがこのアーキテクチャです。

DBへ直接アクセスするのではなく、インスタンス毎にキャッシュを保持する構成です。データに変更があった場合はDB Reader, Writerへmessageを送信します。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1502.png

データ不整合が発生する確率の計算式なども記載してあったので、パフォーマンスと信頼性のバランスを検討する際に使えるかと思います。

パフォーマンスを非常に高くできますが、その分だけ複雑で、テストも難しいです。また、データ不整合の可能性をどうしても含んでしまうので、それを許容できないケースもあるかと思います。

Orchestration-Driven Service-Oriented Architecture

計算リソースやソフトウェアのライセンスが、今よりはるかに高価だった頃の遺産のようなアーキテクチャです。ライセンスを購入しなければならないソフトウェアの機能を、全く関係のないサービス同士で共有してコストカットすることができます。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1601.png

スケーラビリティは比較的高いですが、極端に複雑な構成になります。現在では、新規でこのアーキテクチャを採用する理由は無いと思います。しかし歴史のあるサービスなどではまだ現役で動いているかもしれないので、知っておく意義はあります。

Microservices Architecture

各サービスが独自のDBを持っていて、相互にやり取りをするアーキテクチャです。

https://learning.oreilly.com/api/v2/epubs/urn:orm:book:9781492043447/files/assets/fosa_1701.png

柔軟でパフォーマンスが高く、テストもしやすいです。その代わり極めて複雑なため、育てるのが大変なアーキテクチャです。

ソフトスキル

技術的な知識が必要なのは当然ですが、この本では関係者との交渉、チームマネジメント、日々の学習など、ソフトスキルにも重きを置いていました。

  • アーキテクチャを図解する際の記号の用法

  • 開発者と生産的な関係を築く方法

  • 毎日の勉強にあてるべき時間

などなど、具体的なtipsが多かったです。

所感

著者が一貫して強く主張していたのは、「アーキテクトが抱える問題に問題に一般解は無い」ということです。どんなプロジェクトでも最適なアーキテクチャはありませんし、これさえやればプロジェクトは必ずうまくいく!ようなものもありません。

市場やチームの状況、各関係者の思惑などを見ながら、その状況に合った特殊解を考え続けるのがアーキテクトの仕事です。アーキテクチャ特徴やアーキテクチャスタイルを理解するのは前提として必要だと思いますが、それだけではなく開発者や経営層といい関係でいられるように努力し続けるのが肝心だと思いました。

アーキテクチャ特徴やアーキテクチャスタイルは、リファレンスとしても使いやすいのではないでしょうか。プロジェクトの立ち上げ時などに、ざっと目を通し直すといいかもしれません。

Spring MVCでREST APIを作成して、jQueryでajaxを使用して呼び出す

今回は簡単なGET APIを作成して、それをjQueryajaxで利用してみます。

できること

下記のようなJsonを返すAPIを作成しました。

% curl http://localhost:8080/greeting
{
    "id":1,
    "content":"Hello, World!"
}

このAPIを、jQueryajaxを使用して呼び出し、結果を画面上に埋め込んで表示します。

Jsonの返却

Jsonを返却している箇所は下記のようにしています。

@CrossOrigin
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
}

今回はSpringアプリケーションからHTMLを返却するのではなく、HTMLファイルをブラウザで直接開くようにしました。そのため@CrossOriginアノテーションをつけて、別オリジンからのアクセスを許可しています。@CrossOrigin(origins="任意のURL")とすれば、特定のオリジンのみ許可することも可能です。

Jsonの生成

返却するドメインクラスは下記のようにしました。

public class Greeting {
    @JsonProperty("id")
    private int id;
    @JsonProperty("content")
    private String content;

    public Greeting(int id, String content) {
        this.id = id;
        this.content = content;
    }
}

@JsonPropertyを一つも付けていないとJsonを生成できず、406エラーが返るようになるので注意が必要です。

APIレスポンスの受け取り

下記のようにしてレスポンスを受け取ります。

$(document).ready(() => {
  $.ajax({
    url: "http://localhost:8080/greeting"
  }).then((data) => {
    $('.greeting-id').append(data.id)
    $('.greeting-content').append(data.content)
  })
})

class名greeting-idgreeting-contentを持ったHTMLエレメントを用意しておき、レスポンスをそこに埋め込むようにしています。

<div>
  <p class="greeting-id">The ID is </p>
  <p class="greeting-content">The content is </p>
</div>

動作検証

Springアプリケーションが起動している状態で、public/inde.htmlをブラウザで開きます。 IDとcontentを取得して表示できているのが分かります。

f:id:kyunki:20220120181013p:plain

参考文献

https://spring.io/guides/gs/consuming-rest-jquery/

https://spring.io/guides/gs/rest-service-cors/

SpringでHATEOASなREST APIアプリケーションを作った

Spring HATEOASを使います。

ソースコード全体は↓

https://github.com/bond-kaneko/TrySpringHATEOAS

HATEOASとは

この資料 を参考にして簡単に紹介します。

HATEOASはRESTの拡張版です。ブログAPIを例として、RESTとHATEOASの違いを説明します。例えばブログの詳細をリクエストしたとします。

RESTではリソースをレスポンスとして返すので、この場合は

  • ブログID

  • ブログタイトル

  • 著者名

  • 更新日時

のような値が返ってきます。

HATEOASの場合は、RESTのレスポンスに加えて、そのブログ(リソース)に対して行える操作も返します。 例えば

  • ブログ編集

  • ブログ削除

などです。各操作を行うためのURLの形式をとっている場合が多いです。

HATEOASでは、バックエンドでどのような操作を行えるかを、フロントエンドが知っている必要がないため、フロントエンドとバックエンドをより分離できるのがメリットです。

作ったもの

/greeting?name=Worldへリクエストを送ると、↓のようなレスポンスを返すアプリケーションです。

{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
    }
  }
}

_links以下がリソースに対して行える操作です。今回は単に、同じリクエストを再度行うためのURLを返すようにしています。

レスポンスの作成

レスポンスへ操作を追加する際は、↓のようにしています。

greeting.add(linkTo(methodOn(GreetingController.class).greeting(name)).withSelfRel());

methodOn(GreetingController.class).greeting(name)が今回リクエストを受け取ったメソッドを表していて、それをlinkTo()の引数に渡してやればURLへ変換されます。

greeting.add()を使えるのは、Greeting.javaがSpring HATEOASのRepresentationModelを継承しているためです。

public class Greeting extends RepresentationModel<Greeting> {
    private final String content;

    @JsonCreator
    public Greeting(@JsonProperty("content")String content) {
        this.content = content;
    }
    ...

Jacksonがjavaクラスからjsonへの変換を行う際に、@JsonCreatorが付いたメソッドを使用します。@JsonPropertyで指定されたプロパティ名を元にjsonへの変換が行われます。

動作検証


↓のようなレスポンスが返ってきており、意図した通りに動作しているのが分かります。

% curl http://localhost:8080/greeting                               
{
  "content":"Hello, World!",
  "_links":{
    "self":{
      "href":"http://localhost:8080/greeting?name=World"
  }
}

参考文献

https://spring.io/guides/gs/rest-hateoas/

https://www.slideshare.net/josdirksen/rest-from-get-to-hateoas

SpringでREST APIを呼び出すアプリケーションを作った

REST APIを呼び出して、レスポンスをJavaクラスのインスタンスとして受け取るアプリケーションを作りました。

APIサーバーのモックをローカルにたてて、アプリケーションからモックサーバーへリクエストを送信する構成にしています。

モックサーバー

Json Serverを使用しています。 複雑な設定が不要で、気軽にモックを作成できるツールです。

npmでインストールできます。

% npm install -g json-server

インストールできたらdb.jsonを作成して、

{
  "quotes": {
    "type": "success",
    "value": {
      "id": 10,
      "quote": "{\"id\":1,\"content\":\"Hello, User!\"}"
    }
  }
}

db.jsonを置いているディレクトリで↓コマンドを実行すると、モックサーバーが立ち上がります。

% json-server --watch db.json

デフォルトだと3000番portで起動しているので、↓のように動作確認できます。

 % curl localhost:3000/quotes
{
  "type": "success",
  "value": {
    "id": 10,
    "quote": "{\"id\":1,\"content\":\"Hello, User!\"}"
  }
}    

レスポンスをJavaインスタンスへ変換

APIサーバーからのレスポンスをJavaインスタンスに変換する際はRestTemplateを使います。↓のようにすると、getForObject()第一引数で指定したURLへGETリクエストを送信して、レスポンスをQuoteの形式にマッピングして、インスタンスを生成してくれます。

Quote quote = restTemplate.getForObject("http://localhost:3000/quotes", Quote.class);

ドメインクラス

今回のレスポンスjsonは↓の形式です。

{
  "type": "success",
  "value": {
    "id": 10,
    "quote": "{\"id\":1,\"content\":\"Hello, User!\"}"
  }
}   

これを表現するために、QuoteValue、2つのjavaクラスをドメインクラスとして使用します。

Quote.java

@JsonIgnoreProperties(ignoreUnknown = true)
public class Quote {

  private String type;
  private Value value;

  public Quote() {}
  以下setterとgetter ...

Value.java

@JsonIgnoreProperties(ignoreUnknown = true)
public class Value {

  private Long id;
  private String quote;

  public Value() {}
  以下setterとgetter ...

@JsonIgnoreProperties(ignoreUnknown = true)とすると、ドメインクラスに存在しないプロパティがJsonに含まれていた場合、無視されます。ignoreUnknown = falseにした場合は無視されずにエラーが発生します。

リクエスト送信

アプリケーションの実行時にリクエスト送信、レスポンス変換を行います。変換結果のQuoteをlogに出力して確認できるようにしています。

@SpringBootApplication
public class ConsumingRestApplication {

    private static final Logger log = LoggerFactory.getLogger(ConsumingRestApplication.class);

    ...

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }

    @Bean
    public CommandLineRunner run(RestTemplate restTemplate) throws Exception {
        return args -> {
            Quote quote = restTemplate.getForObject("http://localhost:3000/quotes", Quote.class);
            log.info(Objects.requireNonNull(quote).toString());
        };
    }
}

動作確認

アプリケーションを実行すると↓ログが出力されていて、意図した動作をしているのが分かります。

INFO 33076 --- [           main] c.e.s.SpringBootRestConsumerApplication  : Quote{type='success', value=Value{id=10, quote='{"id":1,"content":"Hello, User!"}'}}

参考文献

https://spring.io/guides/gs/consuming-rest/

SpringBootでシンプルなGET APIを作った

外部システムとの連携のための知識があまり無いと思っていたので、勉強し直すことにしました。

最初は、GETリクエストに対して簡単なレスポンスを返すアプリケーションを作ります。

ソースコード全体は↓にあります。

https://github.com/bond-kaneko/SpringBootRestApp

できること

GETリクエストに対して、下記のようなレスポンスを返します。

{"id":1,"content":"Hello, World!"}%         

Controllerアノテーション

REST API用のControllerを作成する場合、@RestControllerアノテーションをControllerクラスに付けます。 こうすると、@GetMapping@PostMappingなどが使用できるようになります。

@RestController
public class GreetingController {
...

リクエスマッピング

各エンドポイントとメソッドを紐付けるには、@RequestMappingアノテーションを使います。

@RequestMapping(method=RequestMethod.GET, value="/")とすると、ルートパスに対するGETリクエストとアノテーションをつけたメソッドが紐付けられます。 @GetMapping@PostMapping@RequestMapping(method=RequestMethod.GET)と同じ働きをします。

@GetMapping("/greeting")
    public Greeting greeting() {
    ...

クエリパラメータ

メソッドの引数に@RequestParamアノテーションを付ければ、クエリパラメータを受け取れるようになります。

public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
...
    

valueがパラメータkeyで、keyが存在しなかった場合のデフォルト値をdefaultValueで指定できます。

Controllerクラス全体

package com.example.SpringBootRestApp.restservice;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

@RestController
public class GreetingController {
    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}

returnされたGreetingの行方

上記GreetingControllergreeting()ではGreetingインスタンスを返しています。

本来返すべきなのはJSONであって、Greetingインスタンスではないのですが、インスタンスJsonに変換する機能をSpringが提供してくれているので、明示的に変換する必要はありません。

動作検証

クエリパラメータ付きのリクエストに対応できます。

% curl http://localhost:8080/greeting?name=Test
{"id":2,"content":"Hello, Test!"

クエリパラメータが存在しない場合は、デフォルト値を返します。

% curl http://localhost:8080/greeting
{"id":1,"content":"Hello, World!"}