CXF ile Rest Client
Daha önce bir çok kez farklı kütüphanelerle nasıl Rest servisler için client yazılacağına deÄŸinmiÅŸtim. Åžimdi ise benzer ÅŸekilde CXF kullanarak nasıl yapılacağına bakalım. Bu server ki Client ile diÄŸerlerinin en büyük farklı, API’nizi önceden tanımlamamız. Bunu yaparkende sanki Jax-RS servisi yazarmış gibi birebir aynı annotasyonları kullanmamız.
Projenin Yaratılması
Projemizi Spring-Boot kullanarak basit bir web projesi gibi oluÅŸturacağız. Ama sadece CXF ile client tanımlamalarını yapıp, Junit ile test metodu yazacağız. CXF bildiÄŸiniz üzere hem JAX-WS hem JAX-RS implementasyonu içeriyor. Biz JAX-RS implementasyonu tarafından rest client’ı oluÅŸturup, testlerde bu rest client’ını kullnacağız. Test’te ana uygulama da aynı context’i kullandığından projenizde istediÄŸiniz katmanda testteki gibi kullanabilirsiniz.
Intellij üzerinden yeni bir proje yaratıyoruz fakat proje türü olarak Spring Initializr seçiyoruz. Bu bizi bir takım adımlardan götürecek ve uygulamamızı tamamlamış olacağız. EÄŸer intellij kullanmıyorsanız aynı adımları https://start.spring.io/ adresinden de yapabilirsiniz. Intellij’de bu adımları https://start.spring.io/ adresinden temin ediyor.
SpringInitializr’ı seçtikten sonra next dediÄŸimizde, gelen safyadan sadece web kımısnı seçiyoruz. Bundan baÅŸka CXF bağımlılığımız var ama onu sonradan kendimiz ekleyeceÄŸiz. Sonraki ekranlardaki bilgileri ise aÅŸağıdaki gibi dolduruyorum.
- Name:Â cxf-rest-client
- Group: com.bahadirakin
- Artifact:Â cxf-rest-client
- Package: com.bahadirakin.rest
Projemiz oluÅŸtuÄŸuna göre ÅŸimdi CXF için gerekli bağımlılıkları ekleyebiliriz. TüketeceÄŸimiz servis JSON konuÅŸtuÄŸundan aynı zamanda Jackson bağımlılıklarını da ekliyoruz. Jackson nesneden json’a ve json’dan nesneye çevirim yapabilen bir kütüphane. Benim en sevdiÄŸim özelliklerinden biri doÄŸrudan Jaxb annotasyonlarını kullanarak çevirim yapabilmesi.
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> ... <properties> ... <cxf.version>3.0.4</cxf.version> <jackson.version>1.9.13</jackson.version> ... </properties> <dependencies> ... <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-rs-client</artifactId> <version>{cxf.version}</version> </dependency> <!-- Json Serialization Dependencies --> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-jaxrs</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-xc</artifactId> <version>${jackson.version}</version> </dependency> ... </dependencies> ... </project> |
Rest API
Ben servis olarak daha önceki yazı dizisinde oluÅŸturduÄŸum kullanıcı servisini kullanacağımz. Basit bir arayüz içerisinden CRUD iÅŸlemlerini yapmamızı saÄŸlayan bir servis bu. Ama siz isterseniz baÅŸka bir public api’da (GitHub ya da Facebook gibi) kullanabilirsiniz. TüketeceÄŸim servisten kısaca bahsedecek olursam
- https://mysterious-woodland-4843.herokuapp.com/rest/users  adresinden çalışıyor.
- DoÄŸruca bu adrese “GET” isteÄŸinde bulunursanız tüm kullanıcıların listesi geliyor.
- DoÄŸruca bu adrese “POST” isteÄŸinde bulunursanız ve post gövdesinde Json formatında User nesnesi gönderirseniz yeni kullanıcı oluÅŸturuyor. Aynı zamanda oluÅŸturduÄŸu kullanacıyı size cevapta dönüyor.
- Bu adresin devamına id ekleyip “GET” isteÄŸinde bulunursanız id ile iliÅŸkili kullanıcı bilgisini dönüyor. ÖrneÄŸin https://mysterious-woodland-4843.herokuapp.com/rest/users/54fc333ce4b065c0c473d2e1 gibi…
API’ın kullanıcı güncelleme ve silme ile iligli metodları da mevcut. İsterseniz client’ınıza bunlarıda ekleyebilirsiniz. Fakat ben basitlik saÄŸlaması açısından bu kadarla bırakacağım. Anlayacağınız üzere client tarafında tüm API’ı kapsamak zorunda deÄŸilsiniz.
Åžimdi bu metodları bir interface üzerinde JAX-RS annotasyonları ile gerçekleyelim. CXF üzerinden client taratırken bu interface’i kullanacağız. Öncelikle src/main/java altına com.bahadirakin.rest.api isminde bir paket yaratıyoruz. Daha sonra bu paketin altına UserService isminde bir interface yaratıyoruz.
UserInterface.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package com.bahadirakin.rest.api; import javax.ws.rs.*; import java.util.List; @Path("/users") public interface UserService { @GET List<User> findAllUsers(); @GET @Path("/{id}") User findUser(@PathParam("id") String userId); @POST User createUser(User user); } |
CXF ve Spring Ayarları
Kullanacağımız arayüzü yarattığımıza göre şimdi cxf ve spring üzerinden hangi adresten hangi servisi kullanacağımızı belirtelim. Bunun için src/main/resources altına cxf-client-context.xml isminde bir dosya yaratıyoruz ve içeriğini aşağıdaki gibi yapıyoruz.
cxf-client-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs-client="http://cxf.apache.org/jaxrs-client" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs-client http://cxf.apache.org/schemas/jaxrs-client.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <jaxrs-client:client id="userService" serviceName="userService" name="userService" address="https://mysterious-woodland-4843.herokuapp.com/rest" serviceClass="com.bahadirakin.rest.api.UserService" inheritHeaders="true"> <jaxrs-client:headers> <entry key="Accept" value="application/json"/> <entry key="Content-Type" value="application/json" /> </jaxrs-client:headers> <jaxrs-client:providers> <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider"/> </jaxrs-client:providers> </jaxrs-client:client> </beans> |
Burada dikkat etmenizi istediğim kısımlar aşağıdaki gibidir:
- Client yaratırken serviceClass kısmında UserService interface’ini kullandık.
- Servisimizde kullanacağımız header tanımlamalarımızı burada yapabiliyoruz.
- Eğer Http basic authentication kullanacaksak yine burada kullanıcı adı ve şifremizi belirtebiliriz.
Åžimdi ise bu xml dosyamızı ana application context’imize ekleyelim. Spring-Boot tüm varsayılan ayarlarını annotasyon tabanlı yapıyor. Projenizi ilk oluÅŸturduÄŸunuzda da bu sınıfı bizim için oluÅŸturuyor. EÄŸer benimle aynı ismi verdiyseniz bu sınıf CxfRestClientApplication isminde olmalı ve com.bahadirakin.rest paketi altında bulunmalı. Bunun bir eÅŸleniÄŸide test içerisinde olmalı. Bu sınıfın başına ImportResource annotasyonunu kullanarak yeni xml dosyamızı ekliyoruz. Son durumda CxfRestClientApplication sınıfı aÅŸağıdaki gibi oluyor.
CxfRestClientApplication.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package com.bahadirakin.rest; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportResource; @SpringBootApplication @ImportResource(value = {"classpath*:cxf-client-context.xml"}) public class CxfRestClientApplication { public static void main(String[] args) { SpringApplication.run(CxfRestClientApplication.class, args); } } |
Client’ın Test Edilmesi
Tüm ayarları ve tanımlamaları yaptığımıza göre ÅŸimdi client’ımızı test edebiliriz. Bunun için hali hazırda bulunan CxfRestClientApplicationTests sınıfına UserService nesnemizi inject edip yeni bir test yazıyoruz. Son durumda CxfRestClientApplicationTests sınıfı aÅŸağıdaki gibi oluyor. Bu sınıftaki testleri çalıştırdığınızda bir sorun olmadığını ve datanın düzgün gelip gittiÄŸini göreceksiniz.
CxfRestClientApplicationTests.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.bahadirakin.rest; import com.bahadirakin.rest.api.User; import com.bahadirakin.rest.api.UserService; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import java.util.List; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = CxfRestClientApplication.class) @WebAppConfiguration public class CxfRestClientApplicationTests { @Autowired private UserService userService; @Test public void testGetUsers() { final List<User> users = userService.findAllUsers(); Assert.assertNotNull(users); } } |
Son
Bana API olarak tanımlayıp sonrasında tüketmek çok daha mantıklı bir çözüm gibi geldi. Bunu tek yapan kütüphane CXF deÄŸil. Retrofit’te benzer iÅŸlevi yapıyor, üstelik Spring bağımlılığı olmadan. Daha hafif birÅŸey arıyorsanız kesinlikle Retrofit’e de bir bakmanızı tavsiye ederim. Son olarak projenin son haline aÅŸağıdaki adresten ulaÅŸabilirsiniz.
End of line