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 可以呼叫:
GET /api/hello?to={to}
=> 回傳 StringGET /api/hello/{to}
=> 回傳 JSON
可以試著透過瀏覽器呼叫看看!如果能看到正確的回傳值的話,表示 API 已經準備就緒!
如何撰寫 Client
承前述,MPRestClient 是透過註記 @annotation
在 interface
上來撰寫 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,請自行試著呼叫看看!
GET /api/client/1
=> 呼叫GET /api/hello?to={to}
GET /api/client/2
=> 呼叫GET /api/hello/{to}
特別要提醒兩件事情:
- 為了順利注入
SimpleClient
,則HelloClient
必須受 CDI 管理。請依照實際情況加上該加的 scope,如:@ApplicationScoped
。 - 實務上實作邏輯時,請不要採用自己呼叫自己的 RESTful API 這樣的方式。以上做法是為了範例呈現方便,若真有需要,請直接呼叫 API 實際的邏輯就可以了。
文末,做個簡單的結語,
MPRestClient 提供了採用了
JAX-RS
的@annotation
,讓開發 Client 就像是開發 RESTful API 一樣容易,此外,相容於 CDI,讓使用 Client 也變得非常簡單。若有呼叫其它 RESTful API 的需求,請務必考慮使用!!!by Arren Ping