§HTTP ile JSON
Play, HTTP API’nin JSON kütüphanesi ile birlikte kullanılması ile içerik türü JSON olan HTTP istek ve yanıtlarını destekler.
Controller’lar, Action’lar ve yönlendirme hakkında ayrıntılı bilgi için HTTP Programlama sayfasına bakınız.
Gerekli kavramları, varlıkları GET ile almak ve POST ile yaratmak için bir RESTful web servis geliştirerek göstereceğiz. Bu servis tüm veri için içerik türü olarak JSON kullanacak.
Servisimiz için kullanacağımız model aşağıda yer alıyor:
case class Location(lat: Double, long: Double)
case class Place(name: String, location: Location)
object Place {
var list: List[Place] = {
List(
Place(
"Sandleford",
Location(51.377797, -1.318965)
),
Place(
"Watership Down",
Location(51.235685, -1.309197)
)
)
}
def save(place: Place) = {
list = list ::: List(place)
}
}
§Bir varlık listesini JSON biçiminde sunmak
Controller’ımıza gerekli import’ları ekleyerek başlayalım.
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.functional.syntax._
object Application extends Controller {
}
Action
’ı yazmadan evvel modelimizden JsValue
görünümüne dönüşüm yapacak bir bağlantıya ihtiyacımız var. Bu bağlantıyı örtük bir Writes[Place]
tanımlayarak sağlıyoruz.
implicit val locationWrites: Writes[Location] = (
(JsPath \ "lat").write[Double] and
(JsPath \ "long").write[Double]
)(unlift(Location.unapply))
implicit val placeWrites: Writes[Place] = (
(JsPath \ "name").write[String] and
(JsPath \ "location").write[Location]
)(unlift(Place.unapply))
Sonra Action
’ı yazıyoruz:
def listPlaces = Action {
val json = Json.toJson(Place.list)
Ok(json)
}
Action
önce bir Place
listesi elde ediyor, daha sonra bunları örtük Writes[Place]
aracılığıyla Json.toJson
kullanarak bir JsValue
’ya dönüştürüyor ve bu değeri yanıt gövdesi olarak döndürüyor. Play, yanıtı JSON olarak tanıyacak ve yanıt için gerekli Content-Type
başlığı ile gövde değerini setleyecektir.
Geriye yalnızca bu Action
için conf/routes
dosyasına bir yönlendirme eklemek kalıyor:
GET /places controllers.Application.listPlaces
Bu action bir tarayıcı ya da HTTP aracı kullanarak test edilebilir. Bizim örneğimiz UNIX komut satırı aracı cURL kullanıyor.
curl --include http://localhost:9000/places
Yanıt:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 141
[{"name":"Sandleford","location":{"lat":51.377797,"long":-1.318965}},{"name":"Watership Down","location":{"lat":51.235685,"long":-1.309197}}]
§JSON ile yeni bir varlık oluşturmak
Bu Action
için bir JsValue
’dan bizim modelimize dönüşüm yapacak örtük bir Reads[Place]
tanımlamamız gerekiyor.
implicit val locationReads: Reads[Location] = (
(JsPath \ "lat").read[Double] and
(JsPath \ "long").read[Double]
)(Location.apply _)
implicit val placeReads: Reads[Place] = (
(JsPath \ "name").read[String] and
(JsPath \ "location").read[Location]
)(Place.apply _)
Daha sonra Action
’ı tanımlıyoruz.
def savePlace = Action(BodyParsers.parse.json) { request =>
val placeResult = request.body.validate[Place]
placeResult.fold(
errors => {
BadRequest(Json.obj("status" ->"KO", "message" -> JsError.toFlatJson(errors)))
},
place => {
Place.save(place)
Ok(Json.obj("status" ->"OK", "message" -> ("Place '"+place.name+"' saved.") ))
}
)
}
Bu Action
bir öncekinden daha karmaşık. Dikkate alınması gereken bazı noktalar şöyle:
- Bu
Action
,Content-Type
başlığıtext/json
ya daapplication/json
olan ve gövdesi oluşturulacak varlığın JSON görünümünü içeren bir istek bekliyor. - İsteği ayrıştırmak ve
request.body
’yi birJsValue
olarak vermek için JSON’a özel birBodyParser
kullanıyor. - Dönüşüm için örtük
Reads[Place]
kullananvalidate
metodundan faydalanıyoruz. - Doğrulama sonucunu işlemek için hata ve başarı durumlarıyla
fold
kullanıyoruz. Bu desen form gönderiminde de kullanıldığından tanıdık gelebilir. Action
aynı zamanda JSON yanıtları gönderiyor.
Son olarak conf/routes
dosyasına bir yönlendirme ekliyoruz:
POST /places controllers.Application.savePlace
Bu action’ı geçerli ve geçersiz isteklerle test ederek başarı ve hata durumlarımızı doğrulayacağız.
Geçerli veri ile test:
curl --include
--request POST
--header "Content-type: application/json"
--data '{"name":"Nuthanger Farm","location":{"lat" : 51.244031,"long" : -1.263224}}'
http://localhost:9000/places
Yanıt:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 57
{"status":"OK","message":"Place 'Nuthanger Farm' saved."}
“name” alanı olmayan geçersiz veri ile test:
curl --include
--request POST
--header "Content-type: application/json"
--data '{"location":{"lat" : 51.244031,"long" : -1.263224}}'
http://localhost:9000/places
Yanıt:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 79
{"status":"KO","message":{"obj.name":[{"msg":"error.path.missing","args":[]}]}}
“lat” için hatalı veri türüne sahip geçersiz veri ile test:
curl --include
--request POST
--header "Content-type: application/json"
--data '{"name":"Nuthanger Farm","location":{"lat" : "xxx","long" : -1.263224}}'
http://localhost:9000/places
Yanıt:
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 92
{"status":"KO","message":{"obj.location.lat":[{"msg":"error.expected.jsnumber","args":[]}]}}
§Özet
Play, JSON ile REST geliştirmeyi desteklemek üzere tasarlanmıştır. Dolayısıyla bu servisleri geliştirmenin basit olduğunu umuyoruz. İşin çoğu bir sonraki bölümde ayrıntılı olarak açıklanan modeliniz için Reads
ve Writes
yazmaktan ibaret.
Dokümantasyonun bu çevirisi Play ekibi tarafından yapılmamaktadır. Eğer bir hata bulduysanız, bu sayfanın kaynak kodu burada bulunmaktadır. Dokümantasyon yönergelerini okuduktan sonra lütfen katkı yapmaktan çekinmeyin.