MicroProfile Rest Client・呼叫服務啦!

在 RESTful API 大紅大紫之前,Web Service 的世界是以 SOAP 來運作的。SOAP 的資料格式是 XML,有其優點也有其缺點,從現行主流做法來看,毫無疑問地,以 XML 為格式的 SOAP 已鮮少人使用。

在 Java 的世界裡,技術與市場迭代的速度,顯然超越了當時標準制定者的預期。雖然目前規範制定的方式已經改變模式急起直追,但能否成功仍屬未知。無論如何,可以確定的是,現在的 Java 除了面臨自己生態系的競爭,同時,也面臨新的生態系加入爭食伺服器應用的大餅。

服務導向架構(Service Oriented Architecture, SOA)的理念隨著微服務架構(Microservice Architecture)的推展而逐漸實現,其中最重要的概念就是拆分邏輯與服務串連,簡單點理解,就是要能夠呼叫 RESTful API。

無論是因為生態系太強健,或者原本運行的環境沒有這個需求,在 Java SE 11 之前並沒有提供 Http Client。換句話說,除非使用第三方的函式庫,Java SE 的開發者無法直接呼叫任何 RESTful API。
那麼,以開發伺服器應用的 Java EE 又是如何呢?
2009 年 Java EE 6 釋出,新增了 JAX-RS 規格來支援開發 RESTful API,此時規格中並不包含 Client。四年後的 2013 年,Java EE 7 推出的 JAX-RS 2.0 終於提供 Client 開發的支援,然而 Java 生態系伺服器應用的市場,卻早已是 Struts + Spring + Hibernate 的天下。
後續 Java EE 又面臨了更嚴重的困境,也才有了 MicroProfile 的出現。

時序拉回今天,
既然 RESTful API Client 已經在生態系中有了完整支援,那麼,為何仍有 MicroProfile Rest Client(後簡稱 MPRestClient) 的必要呢?
答案依舊是 那些太難用 為了更方便地讓開發者使用!

就和其他 MicroProfile 的規格一樣,MPRestClient 就是貼心(so sweet~❤️
開發者一樣是使用 @annotation 的方式來開發,特別之處在 MPRestClient 採用了大量 JAX-RS@annotation,再次為開發者減輕負擔,只要會用 JAX-RS 開發 RESTful API 等於會開發對應的 Client!


準備 RESTful API

MPRestClient 的使用方式,是將 @annotation 註記在 interface 之上,使用的方式是可利用 CDI 直接 @Inject,最大的便利性就在於,如同使用普通物件呼叫方法那般自然!

首先,我們先來寫個簡單的 API 供 Client 呼叫用:

@ApplicationPath("api")
public class RestConfig extends Application {
}
@Path("hello")
public class SimpleAPI {

    @GET
    public String sayHello1(@QueryParam("to") String to) {
        return "Hello " + to + "!";
    }

    @Path("{to}")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Message sayHello2(@PathParam("to") String to) {
        var message = new Message();
        message.setName(to);
        message.setMessage("Hello World!");
        return message;
    }

    public static class Message {

        private String name;

        private String message;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }
}

照上述利用 JAX-RS@annotation 撰寫後,我們將會有兩個 API 可以呼叫:

  1. GET /api/hello?to={to} => 回傳 String
  2. GET /api/hello/{to} => 回傳 JSON

可以試著透過瀏覽器呼叫看看!如果能看到正確的回傳值的話,表示 API 已經準備就緒!

如何撰寫 Client

承前述,MPRestClient 是透過註記 @annotationinterface 上來撰寫 Client。不多說,直接看:

@RegisterRestClient(baseUri = "http://localhost:8080/api/hello")
public interface SimpleClient {

    @GET
    Response sayHello1(@QueryParam("to") String to);

    @GET
    @Path("{to}")
    Message sayHello2(@PathParam("to") String to);

    public static class Message {

        private String name;

        private String message;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }
}

是不是似曾相識呢?
只要會使用 JAX-RS 來開發 API,透過 MPRestClient 的支援,就能以 JAX-RS 相同的 @annotation 來開發 Client。唯一不同是在 interface 上標記的 @RegisterRestClient,理由是我們將採用 CDI 進行注入,所以為了讓 MPRestClient 可以找到 RESTful API 的位置,所以必須加上這個 @annotation

MPRestClient 另有提供以呼叫函式庫的方式來取得 Client,同時也支援 MPConfig,詳情請閱讀規格書。

如何使用 Client

使用的方法很簡單,只要透過 CDI 注入,剩下的就交由 CDI 來管理!
為了方便測試,我們再寫另一個 RESTful API 來呼叫 Client:

@Path("client")
@ApplicationScoped
public class HelloClient {

    @Inject
    @RestClient
    private SimpleClient client;

    @Path("1")
    @GET
    public String test1() {
        var response = client.sayHello1("HelloClient.test1");
        return response.readEntity(String.class);
    }

    @Path("2")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public SimpleClient.Message test2() {
        var message = client.sayHello2("HelloClient.test2");
        return message;
    }
}

這麼一來,就會新增兩個 RESTful API,請自行試著呼叫看看!

  1. GET /api/client/1 => 呼叫 GET /api/hello?to={to}
  2. GET /api/client/2 => 呼叫 GET /api/hello/{to}

特別要提醒兩件事情:

  1. 為了順利注入 SimpleClient,則 HelloClient 必須受 CDI 管理。請依照實際情況加上該加的 scope,如:@ApplicationScoped
  2. 實務上實作邏輯時,請不要採用自己呼叫自己的 RESTful API 這樣的方式。以上做法是為了範例呈現方便,若真有需要,請直接呼叫 API 實際的邏輯就可以了。

文末,做個簡單的結語,

MPRestClient 提供了採用了 JAX-RS@annotation,讓開發 Client 就像是開發 RESTful API 一樣容易,此外,相容於 CDI,讓使用 Client 也變得非常簡單。若有呼叫其它 RESTful API 的需求,請務必考慮使用!!!

by Arren Ping