JAX-RSでRESTfulAPIの実装

目次

1.RESTfulAPIとは
 REST API (RESTful API) は、REST(Representational State Transfer)アーキテクチャに従い、 コンピュータで提供されるサービスとの対話を可能にするAPIです。RESTはプロトコルなど決められた仕様があるわけではなく、API設計のガイドラインです。
 RESTの4原則(Roy Fielding氏が2000年に提唱)はWebAPIの設計で考えると、
①ステートレスなクライアント/サーバプロトコル
 リクエスト(メッセージ)はその内容を理解するために必要な全ての情報を含むこと。このため、メッセージ間におけるセッションの状態を管理する必要がなく、シンプルな設計にできます。
②すべてのリソースに適用できる定義された操作のセット
 情報(リソース)を操作できる命令(”GET”、”POST”、”PUT”、”DELETE” などに相当するもの)が定義されていること。
③リソースを一意に識別する「汎用的な構文」
 すべてのリソースはUniform Resource Identifier (URI) で一意的に識別できること。
④情報と状態遷移の両方を扱うことができる「ハイパーメディアの使用」
 情報の一部として、別の状態や別の情報への参照を含めることができる。
(参考:Wikipedia「Representational State Transfer」)

2.WebAPIの設計
 RESTアーキテクチャに従い、WebAPIを考えることとします。

2.1 前提条件
 WebAPIは、通信ネットワークを介したリモートのコンピュータ(Webサーバ、又はHTTPサーバ)にあるリソースを要求するためのAPIです。Web APIでは通常、要求メッセージにHTTPを使用し、応答メッセージの構造を定義します。 
 応答メッセージの形式として、通常XMLまたはJSONがあります。ここでは、リクエストにHTTP、応答メッセージの構文としてJSON形式とします。

2.2 前提知識
(1)HTTPプロトコルについて
 ブラウザからHTTPでWebサーバにコンテンツを要求するときの電文は下図のようになります。

 HTTPプロトコルはクライアントからのリクエスト(要求)とサーバからのレスポンス(返信)でデータの受け渡しを行います。
 下記にリクエストとレスポンスの構造を示します。

 ブラウザとWebサーバ間で使うHTTPのメソッドはGETとPOSTの2つで以下のように使い分けています。
①GET
 URLの後にデータ(テキストのみ)を付加して送信します。 
 このため、検索フォームをGET送信するとURLの末尾に「/?パラメーター=値&パラメーター=値・・・」が付加され、履歴から再度検索することなどができます。
②POST
 POST送信はボディ部にデータ(テキスト、バイナリ)を付加するため、URIの履歴に残りません。履歴に残さないフォームの送信時に使います。
 HTTPにはGET、POSTメソッドの他、PUT、DELETEなどがあります。
(参考)
・RFC 2616: Hypertext Transfer Protocol — HTTP/1.1
 https://www.ietf.org/rfc/rfc2616.txt

(2)JSON形式
 JSON(JavaScript Object Notationの略)はJavaScriptのオブジェクトの表記方法の一つでテキスト形式のファイルをJSONファイル(拡張子は.json)といいます。
 JSONは{}の中にキーと値をコロンで区切って記述します。
 キーは必ずダブルクォーテーションで囲む必要があります。
 キーの値は、
 ・文字列 {“name”:”suzuki”}
 ・数値 {“id”:1}
 ・null {“id”:null}
 ・bool値 {“s1″:true,”s2”:false}
 の型が使えます。
  また、値を入れ子にするときは
 ・オブジェクト
  {“id”:1,”mdata”:{“name”:”suzu”,”age”:50}}
 ・配列
  {“id”:1,”code”:[100,300,700]}
 のようにオブジェクトと配列の型が扱えます。

2.3 設計
(1)リソースを決定
 APIの利用者が必要としている情報(リソース)を決めます。天気の情報では、観測地点(緯度経度)、気温、湿度、気圧などが該当します。

(2)リソースに対して提供する操作
 一般ユーザ向けのサービスでは参照のみと思いますが、決められたメンバーを対象とするサービスでは参照、新規登録、更新、削除などが考えられます。

(3)リソースの構造
 WebAPIで定義する操作をデータベースへの登録(新規、更新)、検索、削除を前提にする場合は、データベースの設計(データの正規化など)において、WebAPIの操作とリソースに対してWebサーバ側のデータが一意的に決まるようにしますが、WebAPIで扱うリソースの対象がデータベースにあるものとは限りません。WebAPIのリソース間の親子関係について不整合が生じないようにリソースの構造を決める必要があります。

(4)URI(Uniform Resource Identifier)の設計
 リソースの操作はHTTPメソッドで指示するようにします。 
 APIと分かるようなURIにします。

2.4 公開されているAPIの例
(1)都道府県内市区町村一覧取得API
 HTTPメソッド:GET
 URI:
 https://www.land.mlit.go.jp/webland/api/CitySearch?<パラメータ>
 パラメータ:都道府県コード
(例)東京都内の市区町村一覧を取得する
 https://www.land.mlit.go.jp/webland/api/CitySearch?area=13

(引用)
・API操作説明 – 土地総合情報システム – 国土交通省)
 https://www.land.mlit.go.jp/webland/api.html

(2)NHK番組表API
 HTTPメソッド:GET
 URI:
https://api.nhk.or.jp/v2/pg/list/{area}/{service}/{date}.json?key={apikey}
 パラメータ:
  area:地域ID(3byte)
  sercice:サービスID(2byte)
  date:日付(YYYY-MM-DD形式、当日から1週間先までの日付を指定)
apikey:APIキー(32byte)、ユーザに割り当てられる

 (例)area:130:東京、g1:NHK総合1
 https://api.nhk.or.jp/v2/pg/list/130/g1/2021-12-04.json?key=・・・

(引用)
・NHK番組表API
 https://api-portal.nhk.or.jp/

3.Jerseyを使ったWebアプリの実装
 ここではJAX-RS(Java API for RESTfulServices)フレームワークであるJerseyを使ったRESTfulServicesを作成します。

3.1 開発環境
 Windows10Pro(64bit)
 下記のソフトがインストールされている
 ・Apache Maven 3.8.4
 ・Eclipse JavaEE IDE Version: 2020-12 (4.18.0)
 ・Java version “15.0.2”

3.2 Jerseyのプロジェクト作成
 Jersey(ジャージー)はJAX-RSフレームワークの一つです。ここではjersey-quickstart-webappmavenアーキタイプを使用して、jerseyRESTful APIWebアプリケーションを作成します。
(1)Mavenによるプロジェクトの作成
 Webアプリケーションのプロジェクトを作成します。
 コマンドプロンプトで下記のコマンドを入力します。

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeGroupId=org.glassfish.jersey.archetypes

ここでは、
 grpupId:test
 artifactId:jaxrs-sample1
とします。

下記のプロジェクトフォルダが作成されます。

 MavenはJavaのビルドツールの一つでxmlファイルに記述することでライブラリのインストールなどが行えます。

(本サイト内のコンテンツ)
Mavenプロジェクトの作成(javaビルドツール)

(2)Eclipseにインポート
 ①mvnコマンドで作成したプロジェクトフォルダをEclipseで使えるようにします。
 > cd jaxrs-sample1
 > mvn eclipse:eclipse

②Eclipseにインポート
 ファイル>インポート

③Mavenプロジェクトに変換
 プロジェクト・エクスプローラーでプロジェクトを選択し、右ボタンのメニューから構成>「Mavenプロジェクトへ変換」を選択します。

 JAX-RSのプロジェクトにはデフォルトではサーブレットAPIが組み込まれないためエラーになりますが、ここではサーブレットは使わないため問題ありません。

 JSP/サーブレットを使うときはpom.xmlのに追加します。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

④サーバを起動


 エラーの原因はmavenプロジェクト生成時に作成されたClassファイル「MyResource.java」において、importで指定するライブラリがJakarta EEのものとなっていました。
 また、jerseyのバージョンが3.xとなっていたため、2.xに修正します。
 javaEE(JakartaEE)のJerseyのバージョン
  Jakarta EE 9 :Jersey 3.x 
  Java EE8,EE11 :Jersey 2.x

・「MyResource.java」の修正

/* 修正前
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
*/
/* 修正後 */
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

:

・「pom.xml」の修正

<!-- 修正前 -->
<properties>
    <jersey.version>3.0.3</jersey.version>
</properties> 

<!-- 修正後 -->
<properties>
    <jersey.version>2.22.1</jersey.version>
</properties>

 「MyResource.java」と「pom.xml」を修正してリソースにアクセスできるようになりました。

(3)リソースファイルについて
 ・「MyResouce.java」

package test;
/*
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
*/

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("myresource")
public class MyResource {

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public Employee getIt() {
    	return "Got it!";
    }
}

・アノテーション
①@Path(“myresource”)
 URIは「http://localhost:8080/jaxrs-sample1/webapi/myresource」でリソースにアクセスできます。
 @Pathはこのクラスをマッピングするパスを指定します。
 また、web.xmlのでJerseyのサーブレットをマッピングします。

<servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/webapi/*</url-pattern>
</servlet-mapping>

②HTTPリクエストのJavaメソッドへのマッピング用javax.ws.rsアノテーション
 @GET:HTTPのGETメソッドでアクセスされたとき呼び出されるメソッドで、URIにより識別されるリソースをクライアントに送信します。
 @PUT:URIで識別される特定のリソースの作成(主に更新)を行います。
 @DELETE:URIで識別されるリソースを削除します。
 @POST:URIで識別される特定のリソースの作成(主に新規)を行います。
 @HEAD:GETと同じ役割でレスポンス・ヘッダーのみを返し、メッセージはありません。
③ @Produces(MediaType.TEXT_PLAIN)
 サービスが返すメディアタイプを指定することで、指定された型式でクライアントに返すことができます。

3.3 リソースファイルの改造
 jersey-quickstart-webappmavenアーキタイプではテキストを返すのみでしたが、URIで指定したパラメータに従ってリソース(JSONファイル)を返すように改造します。
(1)RESTAPIのURI仕様
 ・リクエスト
  GET /webapi/myresource/{id}/{name}
・レスポンス
  JSON形式{“id”:id,”name”:name} 

(2)改造内容
 ・「MyResource.java」

package test;
/*
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
*/

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

/**
 * Root resource (exposed at "myresource" path)
 */
@Path("myresource")
public class MyResource {

    /**
     * Method handling HTTP GET requests. The returned object will be sent
     * to the client as "text/plain" media type.
     *
     * @return String that will be returned as a text/plain response.
     */
    @GET
    //@Produces(MediaType.TEXT_PLAIN)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/{id}/{name}")
    public Employee getIt(@PathParam("id") int id,@PathParam("name") String name) {
    	Employee employee = new Employee(id, name);
    	return employee;
        //return "Got it!";
    }
}

 ・「Employee.java」

package test;

public class Employee {
	  /** 番号 */
	  public int id;
	  /** 名前 */
	  public String name;
	  /**
	   * コンストラクタ
	   * @param id 番号
	   * @param name 氏名
	   */
	  public Employee(int id, String name) {
	      this.id = id;
	      this.name = name;
    }
}

 ・「pom.xml」
 Jersey(ジャージー)の拡張モジュール「jersey-media-json-jackson」の追加します。Java オブジェクトと JSON の相互変換を行います。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>test</groupId>
    <artifactId>jaxrs-sample1</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>jaxrs-sample1</name>

    <build>
        <finalName>jaxrs-sample1</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
            <!-- artifactId>jersey-container-servlet</artifactId -->
        </dependency>
        <!-- uncomment this to get JSON support
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
        </dependency>
        -->
        <dependency>
        	<groupId>org.glassfish.jersey.media</groupId>
        	<artifactId>jersey-media-json-jackson</artifactId>
        </dependency>
    </dependencies>
    <properties>
        <jersey.version>2.22.1</jersey.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

リクエストGET /webapi/myresource/{id}/{name}のレスポンスとして、JSON形式{“id”:id,”name”:name}が返ります。

(参考文献)
・JAX-RSフレームワーク
 https://ja.wikipedia.org/wiki/JAX-RS

・Oracle® Fusion Middleware Oracle WebLogic Server RESTful Webサービスの開発と保護
 2 RESTful Webサービスの開発
https://docs.oracle.com/cd/E92951_01/wls/RESTF/develop-restful-service.htm

・「EclipseではじめるJavaフレームワーク入門 第5版」
 著者:掌田津耶乃 発行:株式会社秀和システム

The end