What does the word “Action” do in a Scala function definition using the Play framework?

后端 未结 3 688
你的背包
你的背包 2021-02-02 00:45

I am developing Play application and I\'ve just started with Scala. I see that there is this word Action after the equals sign in the function below and before curl

3条回答
  •  南旧
    南旧 (楼主)
    2021-02-02 01:20

    This word is a part of Play Framework, and it's an object, which has method apply(block: ⇒ Result), so your code is actually:

    def index: Action[AnyContent] = Action.apply({
      Ok.apply(views.html.index("Hi there"))
    })
    

    Your index method returns an instance of the class Action[AnyContent].

    By the way, you're passing a block of code {Ok(...)} to apply method, which (block of code) is actually acts as anonymous function here, because the required type for apply's input is not just Result but ⇒ Result, which means that it takes an anonymous function with no input parameters, which returns Result. So, your Ok-block will be executed when container, received your instance of class Action (from index method), decided to execute this block. Which simply means that you're just describing an action here - not executing - it will be actually executed when Play received your request - and find binding to your action inside routing file.

    Also, you don't have to use def here as you always return same action - val or lazy val is usually enough. You will need a def only if you actually want to pass some parameter from routing table (for instance):

    GET   /clients/:id          controllers.SomeController.index(id: Long)
    
    def index(id: Long) = Action { ... } // new action generated for every new request here
    

    Another possible approach is to choose Action, based on parameter:

    def index(id: Long) = {
       if (id == 0) Action {...} else Action{...}
    }
    

    But uasually you can use routing table itself for that, which is better for decoupling. This example just shows that Action is nothing more than return value.


    Update for @Kazuya

     val method1 = Action{...} //could be def too, no big difference here
    
     // this (code inside Action) gonna be called separately after "index" (if method2 is requested of course)
     // notice that it needs the whole request, so it (request) should be completely parsed at the time
     val method2 = Action{ req => // you can extract additional params from request
       val param1 = req.headers("header1")
       ...
     }
    
     //This is gonna be called first, notice that Play doesn't need the whole request body here, so it might not even be parsed on this stage
     def index(methodName: String) = methodName match {
       case "method1" => method1
       case "method2" => method2
     }
    

    GWT/Scala.js use simillar approach for client-server interaction. This is just one possible solution to explain importance of the parameter "methodName" passed from routing table. So, action could be thought as a wrapper over function that in its turn represents a reference to OOP-method, which makes it useful for both REST and RPC purposes.

提交回复
热议问题