Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
HTTP is the standard protocol for communication between web browsers and web servers. It specifies how a client and server establish a connection, how the client requests data from the server, how the server responds to that request, and finally, how the connection is closed. HTTP connections use the TCP/IP protocol for data transfer. A Play Framework is an open-source web application that follows the model–view–controller architectural pattern. It is written in Scala and makes it easy to build web applications with Java & Scala.
In this blog, we shall now see various features of HTTP programming with the help of the Play framework.
Actions, Controllers, and Results
Action
An Action handles most of the requests received by a Play application.
A play.api.mvc.Action is a (play.api.mvc.Request => play.api.mvc.Result) function which handles a request and generates a result to be sent to the client.
An action returns a play.api.mvc.Result value, showing the HTTP response to send to the web client. In this example Ok constructs a 200 OK response containing a plain/text response body.
Controllers are action generators.
A controller in Play is an object that shows Action values. Controllers are typically declared as classes to take advantage of Dependancy Injection.
The most effortless use case for defining an action generator is a method with no parameters that gives back an Action value:
package controllers
import javax.inject.Inject
import play.api.mvc._
class Application @Inject() (cc: ControllerComponents) extends AbstractController(cc) {
def index = Action {
Ok("It is working!")
}
}
Of course, the action generator method can contain parameters, and the Action closure can capture these parameters:
The HTTP method can be any valid methods supported by HTTP (GET, PATCH, POST, PUT, DELETE, HEAD).
Dependency Injection
The router class that is produced by Play's default routes generator has a function Object() { [native code] } that accepts controller instances and has the annotation @Inject. This indicates that the class is appropriate for dependency injection and that it can also be manually initialised using the function Object() { [native code] }.
Before version 2.7.0, Play permitted the definition of controllers as objects rather than classes through a static routes generator. Since Play no longer depends on static state, that is no longer supported. You can still utilise your static state in a controller that is a class if you so choose.
Manipulating Results
Changing the default Content-Type
The result content type is automatically taken from the Scala value you specify as the response body.
For example:
val textResult = Ok("Hello World!")
Will automatically make/set the Content-Type header to text, while:
val xmlResult = Ok(<message>Hello World!</message>)
will make/set the Content-Type header to application/xml.
Manipulating HTTP headers
You can also add/update any HTTP header to the result:
val result = Ok("Hello World!").withHeaders(CACHE_CONTROL -> "max-age=870", ETAG -> "xx")
Note that setting an HTTP header will discard the previous value on its own if it was there in the original result.
Setting and discarding cookies
They (cookies) are just a special form of HTTP headers but we give a set of helpers to make it simpler.
You can add a Cookie to the HTTP response using:
val result = Ok("Hello world")
.withCookies(Cookie("theme", "blue"))
.bakeCookies()
Also, to discard a Cookie once stored on the Web browser:
val result2 = result.discardingCookies(DiscardingCookie("theme"))
We can also set and then remove cookies as part of the same response:
val result3 = result.withCookies(Cookie("theme", "blue")).discardingCookies(DiscardingCookie("skin"))
Session and Flash scopes
Working with Cookies
It's crucial to realize that Flash and session data are appended to each subsequent HTTP request using HTTP cookies rather than being saved on the server.
Some significant issues result from using cookies to implement Session and Flash.
The amount of data is relatively small (only up to 4 KB).
Despite being able to serialise JSON to the cookie, you can only store string data.
Cookies can disclose sensitive information because the browser can see the information inside.
Only subsequent requests can access cookie information, which is unchangeable for the initial request.
Confusion may occur about the final point. Play must analyze the response information again to see the changed value when you modify the cookie. If you want to ensure the session information is current, you should always pair modification of a session with a Redirect.
Storing data in the Session
As the Session is just a Cookie, it is also an HTTP header. You can control the session data the same way you manipulate other results properties:
Note that this is used to replace the whole session. If you need to add an element to an existing Session, add an element to the incoming session, and define that as new session:
You can get back the incoming Session from the HTTP request:
def index = Action { request =>
request.session
.get("connected")
.map { user =>
Ok("Hello " + user)
}
.getOrElse {
Unauthorized("Oops, you are not connected")
}
}
Discarding the whole session
There is special operation that discards the whole session:
Redirect("/home").withNewSession
Body parsers
An HTTP request conntains a header and a content. The RequestHeader class in Play simulates the header since it is often tiny and can be securely buffered in memory. The body, on the other hand, has the potential to be quite long, thus it is treated as a stream rather than being buffered in memory. Play offers a BodyParser abstraction to map the body stream to an object in memory because many request body payloads are tiny and can be represented in memory.
The standard InputStream cannot be used to read the request body since it is blocking and must wait for data to be available. Play is an asynchronous framework, so this is not an option.
Play instead makes use of the Akka Streams asynchronous streaming library. Although conventional InputStream-based technologies are not suitable for use with Play, Akka Streams and the entire ecosystem of asynchronous libraries around Reactive Streams will provide you with everything you need. Reactive Streams is an SPI that enables many asynchronous streaming APIs to seamlessly work together.
Action composition
This part introduces several ways of defining generic action functionality.
Custom action builders
The Action object we use to express our actions is simply an instance of the ActionBuilder trait, which defines all these methods for building actions. You can declare reusable action stacks that can be used to build actions by implementing your ActionBuilder.
Let's begin with a straightforward example of a logging decorator; we want to record each time this action is called.
The invokeBlock method, which the ActionBuilder uses to build each action, is the first place to implement this functionality.
Now we can utilize Dependancy Injection in your controller to get an instance of the LoggingAction and use it the exact way we use Action:
class MyController @Inject() (loggingAction: LoggingAction, cc: ControllerComponents)
extends AbstractController(cc) {
def index = loggingAction {
Ok("Hello World")
}
}
Since ActionBuilder gives all the different methods of building actions, this also works with, for example, declaring a custom body parser
def submit = loggingAction(parse.text) { request =>
Ok("Got the body " + request.body.length + " bytes long")
}
Content negotiation
Content negotiation enables various representations of the same resource (URI). Writing Web Services that handle many output formats is advantageous (XML, JSON, etc.). The Accept* requests headers are mainly used for server-driven negotiation.
Language
Using the play.mvc.Http.RequestHeader#acceptLanguages, you may obtain the list of permitted languages for a request.
They are retrieved via the Accept-Language header, which ranks them based on their quality value.
Content
Similarly, the play.mvc.Http.RequestHeader#acceptedTypes method shows the list of acceptable result’s MIME types for a request. It retrieves them from the Accept request header and sorts them according to their quality factor.
You can test whether a given MIME type is acceptable for the current request using the play.mvc.Http.RequestHeader#accepts method:
public Result list(Http.Request request) {
List<Item> itm = Item.find.all();
if (request.accepts("text/html")) {
return ok(views.html.Application.list.render(itm));
} else {
return ok(Json.toJson(itm));
}
}
Intercepting HTTP requests
Play’s Java APIs provide 2 ways of intercepting action calls. The first is called ActionCreator, which gives a createAction method used to create the initial action in action composition. It handles calling the actual method for your action, which makes you to intercept requests.
The other way is to implement your own HttpRequestHandler, the primary entry point for all HTTP requests in Play. This includes requests from both Scala and Java actions.
Action creators
This interface has 2 methods that can be implemented:
createAction: It takes the request and the controller’s action method associated with the passed request. The action can be the first or last action depending on the configuration setting play.http.actionComposition.executeActionCreatorActionFirst.
wrapAction: It takes the action to be executed and enables the addition of a final global interceptor. Since createAction and the setting mentioned above can accomplish the same, this method is no longer recommended.
There is also a DefaultActionCreator interface which we can extend with default implementations.
HTTP request handlers
Sometimes an application will want more complex functionality than Play's abstractions can provide. When this is the case, applications can offer unique implementations of Play's HttpRequestHandler, the lowest level HTTP pipeline API.
A custom HttpRequestHandler should only be used as a last resort. By using a custom router or filter, the majority of specialised requirements can be satisfied.
Implementing a custom request handler
The HttpRequestHandler interface has 1 method to be implemented, handlerForRequest. It takes the request to get a handler for, and returns a HandlerForRequest instance containing a RequestHeader and a Handler.
Configuring the http request handler
If you are using BuiltInComponents to construct your app, override the httpRequestHandler method to return an instance of your custom handler.
If you use runtime dependency injection (e.g. Guice), the request handler can be dynamically loaded at runtime. The easiest way is to make a class in the root package called RequestHandler that implements HttpRequestHandler.
If you do not want to place your request handler in the root package, or if you want to be able to configure various request handlers for different environments, it can be done by configuring the play.http.requestHandler configuration property in application.conf:
Scala is an advanced version of Java which was made to eliminate unnecessary code. It supports multiple Libraries and APIs which will allow the programmer to achieve Less Down Time.
What is HTTP?
The Hypertext Transfer Protocol is an application layer protocol in the Internet protocol suite model for distributed, collaborative, hypermedia information systems
Conclusion
In this article, we have discussed Scala developers- HTTP programming. We also looked at Actions, Controllers and Results, HTTP Routing, Manipulating HTTP results, Session and Flash scopes, Body parsers, Actions composition and Handling errors.
We hope this blog has helped you understand better. If you would like to learn more. Check out our articles on AWS, AWS Certification, and Cloud Computing. Practice makes a man perfect. To practice and improve yourself in the interview. You can check out Top 100 SQL problems, Interview experience, Coding interview questions, and the Ultimate guide path for interviews.