Pazar, Ağustos 07, 2011

Hızlı Bir Başlangıç - RESTful Web Servisler (JAX-RS)

Önce biraz teori;
Kısaca REST,  tüm bilgilerin kendilerine has birer adrese yani URI (Uniform Resource Idetifier) ‘ye sahip olmasını öngören mimari yaklaşımdır. (Web üzerindeki linkleri buna örnek olarak verebiliriz).
RESTful Web servisler ise REST mimarisini temel alarak geliştirilen web servislerdir yani SOAP yaklaşımı ile web’den uzaklaşan web servislerin tekrar web ile buluşmasıdır. RESTful tasarlanan web servisler web üzerindeki linklere dönüşmüşlerdir ve client ile server arasındaki iletişim stateless bir iletişim protokolü (genellikle HTTP) üzerinden sağlanır.
RESTful Web servislerin Java dünyasındaki standartları JAX-RS spesifikasyonu ile çizilmiştir.
Bu kadar teoriden sonra RESTful Web servislerin nasıl çalıştığını bir örnek üzerinden inceleyelim.
Not: Örnek için geliştirme ortamı olarak Eclipse (mümkünse Maven plugin’i kurulmuş) ile devam edeceğim. Maven kullanmak istemeyenler gerekli kütüphaneleri kendileri eklemek durumunda.

1) Proje oluşturulması

Öncelikle işe bir maven web projesi oluşturarak başlıyoruz. Projemizin adı “restfulwssample” olsun.
Bunun için File –> New –> Others –> Maven Project yolunu izliyoruz. Bu aşamada Maven kullanmak istemiyorsanız yada daha sonra aktif hale getirmek isterseniz “Dynamic Web Project” seçeneği ile ilerleyebilirsiniz.




Sonraki ekranda “Maven Project” seçeneği ile devam ediyoruz.




Sonrasında “Next” tuşlarıyla ilerleyip archetype seçim ekranı geldiğinde “maven-archetype-webapp” seçeneği ile ilerliyoruz.




Sonraki ekrandaki bilgiler tamamen size kalmış, bu bilgileride doldurduktan sonra “Finish” butonu ile web projemizin taslağını oluşturmuş oluyoruz.




Projemizin aşağıdaki gibi görünmesi gerekiyor.




Projemiz hazır. RESTful web servisler hazırlamamız için önmüzdeki tek engel RESTful Web servis için kullanılacak kütüphaneyi bulmamız. Ben bu örnekte Jersey kütüphanesi kullanacağım. JAX-RS spesifikasyonu için referans implementasyon olmasının yanı sıra production ortamlarında da kullanılabilecek olgunluğa sahip olduğu için Jersey’i tercih ettim. Projemizde Jersey kullanabilmek için pom.xml’e aşağıdaki satırları eklememiz yeterli olacaktır.

<repositories> 
<repository>
<id>maven2-repository.java.net</id>
<name>Java.net Repository for Maven</name>
<url>http://download.java.net/maven/2/</url>
<layout>default</layout>
</repository> 
<repository>
<id>maven-repository.java.net</id>
<name>Java.net Maven 1 Repository (legacy)</name>
<url>http://download.java.net/maven/1</url>
<layout>legacy</layout>
</repository>
<repositories>
<dependencies>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.6</version>
</dependency>
<dependencies>

Not: Jersey kullanarak text/html, xml, json gibi farklı yöntemler kullanarak haberleşen web servisler tasarlanması mümkün. Ben örnekte JSON kullanacağım için onunla ilgili dependency’i ekledim. Detalı bilgi için http://jersey.java.net/nonav/documentation/latest/user-guide.html adresine göz atmanızda fayda var.


2) Biraz kod görelim


Örneğimiz için iki sınıf kullacağız. Bunlardan biri RESTful web servisi barındıran sınıf (RSWebServices.java) diğeri ise bu servisin çıktısını temsil eden veri transfer sınıfı (RSOutputDTO.java)

Sınıfları aşağıdaki paket yapısında oluşturalım.





RSOutputDTO.java
package com.blogspot.emrahkocaman.restfulws.json;
public class RSOutputDTO {
private String userName;
private int userAge;
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
public int getUserAge() {
return userAge;
}
}

Bu sınıf web servisimizin üreteceği çıktıyı temsil eden basit bir java sınıfı namı diğer POJO.


RSWebServices.java
package com.blogspot.emrahkocaman.restfulws.ws;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.blogspot.emrahkocaman.restfulws.json.RSOutputDTO;
@Path("/examples")
public class RSWebServices {
@GET
@Path("/getUserInfo")
@Produces(MediaType.APPLICATION_JSON)
public RSOutputDTO getUserInfo() {
RSOutputDTO out = new RSOutputDTO();
out.setUserAge(30);
out.setUserName("Kamil");
return out;
}
}

Web servisimiz bu sınıftan ibaret. SOAP mimarisindekinin aksine xml konfigürasyonları ve xsd’ler ile boğuşmak zorunda değiliz. Doğrudan hedefe yapılan bir atış.

@Path: Sınıf tanımının üzerindeki annotation, web servise ulaşacağımız kök tanımı. Method üzerindeki ise methoda ulaşacağımız tanım. Yani web servis adresimiz http://server:port/examples/getUserInfo gibi bir adres olacak.

@GET: RESTful web servisler HTTP protokülü üzerinden haberleşirler sonuç olarak HTTP operasyonlarına karşılık gelecek annotationlar ile kullanılırlar (@GET, @PUT, @POST, @DELETE and @HEAD gibi). Bizim servisimizin GET isteklerine cevap vereceğini işaretliyoruz.

@Produces: RESTful web servisin çıktısının hangi türde olacağı bu annotation ile belirtilir. Biz örneğimizde JSON kullanıyoruz.


3) Son rötüşlar


RESTful web servisimizi dünyaya açmanın zamanı geldi. Öncelikle Jersey servletini ayağa kaldırmamız gerekiyor.

Bunun için web.xml’e aşağıdaki satırları ekyelim.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>restfulwssample</display-name>
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.blogspot.emrahkocaman.restfulws.ws</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>

Servlet’in aldığı parametrelerden com.sun.jersey.config.property.packages parametresi hangi paketin altındaki sınıfların web servis olarak açılacağını belirtiyor.

com.sun.jersey.api.json.POJOMappingFeature parametresini “true” olarak set ederek ise POJO’larımız jackson kütüphanesi kullanılarak Jersey tarafından otomatik olarak JSON’a dönüştürülüyor.

Web projemizi sunucumuza deploy ettikten sonra,

http://localhost:8080/restfulwssample/rest/examples/getUserInfo adresini browser’a girdiğimiz zaman restful web servisimize ulaşmış olacağız. Bize dönen JSON nesnesini bir text editör ile açtığımızda içeriğinin aşağıdaki gibi olması gerekiyor.

{"userName":"Kamil","userAge":30}

Bundan sonra RESTful ile yapabilecekleriniz size kalmış. Ama bence web servis yazmak hiç bu kadar kolay olmamıştı.

Bir sonraki yazımda hazırladığımız RESTful web servis için bir Android istemci yazıyor olacağız.

Herkese iyi çalışmalar.

Eclipse Projesi : http://db.tt/PCS4UrX

12 yorum:

  1. Tebrik ederim yegenim ;) Basari ve calismalarinin devamini dilerim...

    YanıtlaSil
  2. Bu yorum yazar tarafından silindi.

    YanıtlaSil
  3. çok işime yaradı teşekkürler..

    YanıtlaSil
  4. Merhaba öncelikle bu kaynağın bana fazlasıyla yardımı dokundu. Bunun için teşekkür ederim. Benim bir sorunum var ben bu uygulamayı Windows 7 x64 platformunda çalıştırdım. Fakat sizin verdiğiniz "http://localhost:8080/restfulwssample/rest/examples/getUserInfo" linkini yazınca resimde gördüğünüz hatayı alıyorum. Sizde sorun nerede sizin vermiş olduğunuz proje dosyasını indirip onun üzerinde denedim. Elle herhangi bir kod yazmadım.
    Resim : http://i.imgur.com/CQir5dZ.jpg

    YanıtlaSil
    Yanıtlar
    1. Selam, linkteki resme ulaşamadım.

      Sil
    2. Hocam resim açılıyor şuanda belki bir anlık hata oldu ondan dolayı açılmadı sizin pc de. Hata şu :
      Http status 404
      type : status report
      description : the requested resource is not available.

      Aslında hata sizinde anladığınız gibi kaynak bulunamıyor diyor. Bu projeyi "Tomcat" üzerinde çalıştırınca ek bir şey yapmam gerekiyor mu ? Yani oluşturduğunuz sınıfları ayrıca derlemek gerekiyor mu ? Onuda denedim onda da main kısmı olmadığı için sınıfları da derlemedi.

      Sil
    3. Örnek uygulamayı ben indirip deploy ettiğimde sorun olmadı. Sende çalışmamasının bir kaç sebebi olabilir.
      -Sunucu açılırken hata alıyor olabilir
      -Uygulamayı sunucuya eklememiş olabilirsin
      -Projeyi eclipse'e import ettikten sonra bir hata sebebiyle derlenmemiş olabilir. (Örneğin eclipse üzerinde maven plugin'i olması gerekiyor)

      Sil
  5. geri dönüş tipi örnekteki gibi bir kişi nesnesi olduğunda http 500 hatası veriyor. hatanın linki,
    http://k1305.hizliresim.com/19/5/mspgh.png

    ama geri dönüş tipini stringe çevirip text olarak herhangi bir şeyler return ettğimde sorun ortadan kalmıyor. fikriniz nedir hocam ?

    YanıtlaSil
    Yanıtlar
    1. Sunucu loglarında hatayla ilgili stacktrace olmalı diye düşünüyorum. O kontrol edilebilir.

      Sil
  6. bu konun hakkında bu kadar detaylı bulduğum belki de tke Türkçe kaynak bunun için tebrik ederim çalışmalarınızın devamını dilerim.

    YanıtlaSil
  7. Merhaba,
    Örnek için teşekkürler.
    Spring Restful Web Servise konusu ile de ilgileniyorsanız,
    Spring Framework ile Restful Web Service Nasıl Yazılır? konulu videomu aşağıdaki adresten kontrol edebilirsiniz.

    http://www.bilgicekici.com/2015/07/05/spring-framework-ile-restful-webservice/

    YanıtlaSil
  8. Merhaba,

    eclipse üzerinde maven plugin olduğu halde, çalışmıyor. İlk kendim yazarak denedim çalışmadı, ardından sizin projenizi eclipse ekledim yine çalışmadı. requested resource is not avaliable hatası alıyorum.

    YanıtlaSil