Documentation

You are viewing the documentation for the 2.3.x release series. The latest stable release series is 2.4.x.

§Action birleştirme

Bu bölüm genel action işlevselliği tanımlamanın birçok yolunu göstermektedir.

§Özel action yapıcılar

Daha önce action tanımlamanın istek parametresi ile, istek parametresi olmadan, gövde ayrıştırıcı ile vb. olmak üzere pek çok yolu olduğunu görmüştük. Aslında asenkron programlama bölümünde göreceğimiz üzere bundan çok daha fazlası var.

Action oluşturmak için kullanılan tüm bu metotlar ActionBuilder isimli bir trait içinde tanımlanmışlardır. Action’larımızı tanımlamak için kullandığımız Action nesnesi yalnızca bu trait’in bir örneğidir.

Önce bir loglama örneği ile başlayalım. Bu action’a yapılan her çağrıyı loglamak istiyoruz.

Bunun ilk yolu bu özelliği ActionBuilder tarafından üretilen her action için çağrılan invokeBlock içinde gerçeklemektir:

import play.api.mvc._

object LoggingAction extends ActionBuilder[Request] {
  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
    Logger.info("Calling action")
    block(request)
  }
}

Şimdi bunu Action’ı kullandığımız şekilde kullanabiliriz:

def index = LoggingAction {
  Ok("Hello World")
}

ActionBuilder action oluşturmanın tüm yollarını sağladığından bu yöntem örnek olarak özel gövde ayrıştırıcı ile de çalışır:

def submit = LoggingAction(parse.text) { request =>
  Ok("Got a body " + request.body.length + " bytes long")
}

§Action’ları birleştirmek

Çoğu uygulamada birden fazla action yapıcıya ihtiyaç duyarız. Bunlardan kimi değişik türde yetkilendirme yaparken, diğerleri başka işlevler sağlayabilir. Hangi durum olursa olsun her bir action yapıcı için loglama kodumuzu tekrar tekrar yazmak istemeyiz. Aksine bu özelliği tekrar kullanılabilir şekilde tanımlamak isteriz.

Tekar kullanılabilir action kodu action’ları sarmalayarak gerçeklenebilir:

import play.api.mvc._

case class Logging[A](action: Action[A]) extends Action[A] {

  def apply(request: Request[A]): Future[Result] = {
    Logger.info("Calling action")
    action(request)
  }

  lazy val parser = action.parser
}

Ayrıca Action action yapıcısını da kendi action sınıfımızı tanımlamadan action oluşturmak için kullanabiliriz:

import play.api.mvc._

def logging[A](action: Action[A])= Action.async(action.parser) { request =>
  Logger.info("Calling action")
  action(request)
}

Action’lar action yapıcılar içine composeAction metodunu kullanarak dahil edilebilirler:

object LoggingAction extends ActionBuilder[Request] {
  def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
    block(request)
  }
  override def composeAction[A](action: Action[A]) = new Logging(action)
}

Yapıcı artık önceki gibi kullanılabilir:

def index = LoggingAction {
  Ok("Hello World")
}

Sarmalayan action’ları action yapıcı kullanmadan da dahil edebiliriz:

def index = Logging {
  Action {
    Ok("Hello World")
  }
}

§Daha karmaşık action’lar

Şu ana dek gelen isteği pek de etkilemeyen action’ları gösterdik. Elbette gelen istek nesnesini okuyabilir ve değiştirebiliriz:

import play.api.mvc._

def xForwardedFor[A](action: Action[A]) = Action.async(action.parser) { request =>
  val newRequest = request.headers.get("X-Forwarded-For").map { xff =>
    new WrappedRequest[A](request) {
      override def remoteAddress = xff
    }
  } getOrElse request
  action(newRequest)
}

Not: Play dahili olarak X-Forwarded-For başlık desteğine sahiptir.

İsteği engelleyebiliriz:

import play.api.mvc._

def onlyHttps[A](action: Action[A]) = Action.async(action.parser) { request =>
  request.headers.get("X-Forwarded-Proto").collect {
    case "https" => action(request)
  } getOrElse {
    Future.successful(Forbidden("Only HTTPS requests allowed"))
  }
}

Son olarak dönen yanıtı değiştirebiliriz:

import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits._

def addUaHeader[A](action: Action[A]) = Action.async(action.parser) { request =>
  action(request).map(_.withHeaders("X-UA-Compatible" -> "Chrome=1"))
}

§Farklı istek türleri

Action birleştirme HTTP istek ve yanıt seviyesinde ek işlem yapmanıza izin veriyor olsa da çoğu zaman isteğe bağlam ekleyen ya da istek üzerinde doğrulama yapan veri dönüştürme hatları oluşturmak isteyeceksiniz. ActionFunction istek üzerinde bir fonksiyon olarak düşünülebilir ve hem istek türü hem de bir sonraki katmana geçirilen yanıt türünde parametriktir. Her action fonksiyonu yetkilendirme, veritabanı araması, izin kontrolleri ve action’lar arasında tekrar kullanmak isteyebileceğiniz diğer işlemler gibi modüler işlemleri betimleyebilir.

Farklı türde işlemler için kullanışlı olan ve ActionFunction’ı implement eden birkaç öntanımlı trait bulunmaktadır:

invokeBlock metodunu implement ederek kendi ActionFunction tanımınızı yapabilirsiniz. Genellikle girdi ve çıktı türlerini Request örneği (WrappedRequest kullanarak) olarak tanımlamak uygundur ancak zorunlu değildir.

§Kimlik doğrulama

Action fonksiyonları için en yaygın kullanım durumlarından bir kimlik doğrulamadır. Kullanıcıyı orijinal istekten alıp yeni bir UserRequest içine ekleyen bir action dönüştürücüyü kolayca yazabiliriz. Bunun da girdi olarak Request aldığı için aslında bir ActionBuilder olduğuna dikkat edin.

import play.api.mvc._

class UserRequest[A](val username: Option[String], request: Request[A]) extends WrappedRequest[A](request)

object UserAction extends
    ActionBuilder[UserRequest] with ActionTransformer[Request, UserRequest] {
  def transform[A](request: Request[A]) = Future.successful {
    new UserRequest(request.session.get("username"), request)
  }
}

Play aynı zamanda dahili bir kimlik doğrulama action yapıcı sağlar. Nasıl kullanılacağı hakkında daha fazla bilgi burada bulunabilir.

Not: Dahili kimlik doğrulama action yapıcı yalnızca basit kullanım durumları için gereken kod miktarını en aza indirmek için sağlanan bir yardımcıdır ve gerçeklemesi yukarıdaki örneğe çok benzer şekildedir.

Eğer dahili kimlik doğrulama action tarafından sağlanabileceğinden daha karmaşık gereksinimleriniz varsa kendizinkini gerçeklemeniz hem kolaydır hem de tavsiye edilir.

§İsteklere bilgi eklemek

Şimdi Item türünden nesneler üzerinde işlem yapan bir REST API düşünün. /item/:itemId yolu altında pek çok yol olabilir ve bunların her biri öğeyi veritabanından sorgulama ihtiyacı duyabilir. Bu durumda sorgulama işini bir action fonksiyonu içine koymak kullanışlı olabilir.

Önecelikle UserRequest içine bir Item ekleyen bir istek nesnesi oluşturacağız:

import play.api.mvc._

class ItemRequest[A](val item: Item, request: UserRequest[A]) extends WrappedRequest[A](request) {
  def username = request.username
}

Daha sonra öğeyi sorgulayan ve bir hata (Left) ya da yeni bir ItemRequest (Right) içeren bir Either döndüren bir action arıtıcı tanımlayacağız:

def ItemAction(itemId: String) = new ActionRefiner[UserRequest, ItemRequest] {
  def refine[A](input: UserRequest[A]) = Future.successful {
    ItemDao.findById(itemId)
      .map(new ItemRequest(_, input))
      .toRight(NotFound)
  }
}

§İstekleri doğrulamak

Son olarak bir action fonksiyonunun isteğin devam edip etmemesine karar vermesini isteyebiliriz. Örneğin UserAction’dan gelen kullanıcının ItemAction’dan gelen öğeye erişim yetkisi olup olmadığını kontrol etmek ve yetkisi yoksa hata dönmek istiyor olabiliriz:

object PermissionCheckAction extends ActionFilter[ItemRequest] {
  def filter[A](input: ItemRequest[A]) = Future.successful {
    if (!input.item.accessibleByUser(input.username))
      Some(Forbidden)
    else
      None
  }
}

§Hepsini bir araya getirmek

Şimdi tüm bu action fonksiyonlarını (bir ActionBuilder başlayarak) bir action oluşturmak için andThen kullanarak bir araya getirebiliriz:

def tagItem(itemId: String, tag: String) =
  (UserAction andThen ItemAction(itemId) andThen PermissionCheckAction) { request =>
    request.item.addTag(tag)
    Ok("User " + request.username + " tagged " + request.item.id)
  }

Play ayrıca global kestirme ihtiyaçları için bir global filtre API sağlar.

Sonraki: İçerik müzakeresi


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.