DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Distributing Data and Logic: Enhancing Performance, Resilience, and Efficiency With Akka
  • All the Cloud’s a Stage and All the WebAssembly Modules Merely Actors
  • Writing a Chat With Akka
  • Video Streaming With Akka Streams

Trending

  • 5 Layers of Prompt Injection Defense You Can Wire Into Any Node.js App
  • LLM Integration in Enterprise Applications: A Practical Guide
  • You Are Using Claude Wrong (And So Is Everyone You Know)
  • Getting Started With Agentic Workflows in Java and Quarkus
  1. DZone
  2. Coding
  3. Java
  4. Rejection in Akka HTTP: Handle Errors Properly

Rejection in Akka HTTP: Handle Errors Properly

Learn more about rejection in Akka HTTP and how it helps in handling error scenarios in your application.

By 
Praful Bangar user avatar
Praful Bangar
·
Jan. 21, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
16.5K Views

Join the DZone community and get the full member experience.

Join For Free

Learn more about rejection in Akka HTTP and how it helps in handling error scenarios in your application.


In this blog, we will demonstrate rejection in the Akka HTTP and how it helps in handling error scenarios in our application. Let's get started.

The concept of rejection in Akka HTTP helps to properly deal with error scenarios. For example, with a filtering directive, like the get directive, it does not allow the request to pass through its inner route. As the filter condition is not satisfied, a rejection concept is invoked.


The ~ (Tilde) operator is also called the chaining operator. As it is used to connect two or more paths, the Request allows flowing through the routing structure. And try to find another route that can complete it. If a request does not find any route, it will generate a rejection.

By default, a response for rejected requests was generated by the “handle not found” method of  RejectionHandler.

Scala
 




xxxxxxxxxx
1


 
1
trait RejectionHandler extends (immutable.Seq[Rejection] ⇒Option[Route])



 We will understand this in detail through the following example:

Scala
 




xxxxxxxxxx
1


 
1
val route: Route =
2
 path("hello") {
3
   get {
4
     complete(HttpResponse(entity = "Hello world"))
5
   }    } ~
6
   path("ping") {
7
     get {
8
       complete(HttpResponse(entity = "PONG!"))  }
9
 }



If we access the path with “hello,” then we will get the response “Hello world.” At the same time, we will get a response “PONG!” for the route “ping.”

You may have questions like: "What happens if we hit any other route?" We’ll get the following response: “The requested resource could not be found.”

If we want this response in a more descriptive way, we can customize the RejectionHandler. The easiest way to construct a RejectionHandler is with RejectionHandler.newBuilder() that Akka HTTP provides.

Refer to following code snippet:

Scala
 




xxxxxxxxxx
1
10


 
1
implicit def rejectionHandler = RejectionHandler.newBuilder()
2
 .handleNotFound {
3
 complete(HttpResponse(NotFound,   entity = HttpEntity(ContentTypes.`application/json`, Json.stringify(
4
     Json.toJson(
5
       ErrorResponse(
6
         NotFound.intValue, "NotFound", "The requested resource could not be found.")
7
     )
8
   )
9
 )))
10
}



We’ll get the response as follows:

Java
 




xxxxxxxxxx
1


 
1
{
2
   "code": 404,
3
   "message": "NotFound",
4
   "reason": "The requested resource could not be found."
5
}



Where  ErrorResponse is the case class:

 case class ErrorResponse(code: Int, message: String, reason: String) 

There are three helper methods in RejectionHandler:

1. handleNotFound(Route):

As described in the above example, “Resource Not Found” is special. As it is represented with an empty rejection set, the handle not found helper lets you specify the “recovery route” for this case.

2. handle(PartialFunction[Rejection, Route]):

Handles provided the type of rejection with given partial function. This partial function produces a route, which is run when certain rejection occurs.

3. handleAll[T <: Rejection: ClassTag](f: immutable.Seq[T] => Route):

Handles all rejections of a certain type at the same time. This is useful for cases where you need access to more than the first rejection of a certain type, e. g. for producing the error message to an unsupported request method.

There are many predefined rejections that are provided by Akka HTTP. They are MethodRejection,  AuthorizationFailedRejection, MissingCookieRejection, and  MissingQueryParamRejection.

We invoked these handle calls through implicit definition using “newBuilder()” to build a new  RejectionHandler. We can tell this handler how to handle a particular rejection.

1. MethodRejection:

This rejection occurs when a user uses an unsupported method to access request. In the following example, a supported method is get. This will generate a rejection when we try to access using post,  put, or any other method.

Scala
 




xxxxxxxxxx
1
20


 
1
val route: Route =
2
 path("hello") {
3
   get {
4
     complete(HttpResponse(OK,   entity = HttpEntity(ContentTypes.`application/json`, Json.stringify(
5
       Json.toJson(
6
         ProperResponse(
7
           OK.intValue,"Hello world")))
8
     )))}
9
 }
10
implicit def rejectionHandler = RejectionHandler.newBuilder()
11

          
12
 .handleAll[MethodRejection] { methodRejections =>
13
 val names = methodRejections.map(_.supported.name)
14
 complete(HttpResponse(MethodNotAllowed,   entity = HttpEntity(ContentTypes.`application/json`, Json.stringify(
15
   Json.toJson(
16
     ErrorResponse(
17
       MethodNotAllowed.intValue, "Method Rejection", s"Method not supported! Supported for : ${names mkString "or"}!"))
18
 )
19
 )))
20
}
14
 complete(HttpResponse(MethodNotAllowed,   entity = HttpEntity(ContentTypes.`application/json`, Json.stringify(



For unsupported method, the output will be: 

Java
 




xxxxxxxxxx
1


 
1
{
2
   "code": 405,
3
   "message": "Method Rejection",
4
   "reason": "Method not supported! Supported for : GET!"
5
}



2. MissingQueryParamRejection:

MissingQueryParamRejection arises when the user doesn't mention the required parameters in  Request.

In the given example, if we hit URL, localhost:8080/paint?color = red.

In this scenario, the Response would be:

Request has missing required query parameter for = ‘bgColor’.

And if we hit URL, we get “localhost:8080/paint?bgColor = red." Then, Response will be: Request has missing required query parameter for = ‘color’.

When we mention both parameters in the URL localhost:8080/paint?bgColor=red&color=blue, then we get the proper result:

Java
 




xxxxxxxxxx
1


 
1
{
2
   "code": 200,
3
   "message": "You mention color is blue and background color is red"
4
}



3. AuthorizationFailedRejection:

This Rejection is created by the “authorize” directive. This signals that the request was rejected because the user is not authorized. 

Let’s see an example:

Scala
 




xxxxxxxxxx
1
26


 
1
val route: Route =
2
path("login") {
3
   parameters('username, 'password) {
4
     (username, password) =>
5
       if (username.equals("knoldus") && password.equals("pune")) {
6
         complete(HttpResponse(NotFound,entity = HttpEntity(ContentTypes.`application/json`, Json.stringify(
7
           Json.toJson(
8
             ProperResponse(
9
               OK.intValue, "Login Successful")))
10
         )))}
11
        else {
12
         reject(AuthorizationFailedRejection)
13
       }  } }
14

          
15
implicit def rejectionHandler =
16
 RejectionHandler.newBuilder()
17
.handle { case AuthorizationFailedRejection =>
18
 complete(HttpResponse(BadRequest,   entity = HttpEntity(ContentTypes.`application/json`, Json.stringify(
19
   Json.toJson(
20
     ErrorResponse(
21
       BadRequest.intValue, "AuthorizationFailedRejection", "You have entered invalid credentials")
22
   )
23
 )
24
 )))
25
}
26

          
23
 )



If we hit the path with the right credential values, such as “localhost:8080/login?username = knoldus&password = pune,” we will get a response as:

Java
 




xxxxxxxxxx
1


 
1
{
2
   "code": 200,
3
   "message": "Login Successful"
4
}



When we try to provide access with the wrong values, like “ localhost:8080/login?username = software&password = abcd, ” we will get a response as:

Java
 




xxxxxxxxxx
1


 
1
{
2
   "code": 400,
3
   "message": "AuthorizationFailedRejection",
4
   "reason": "You have entered invalid credentials"
5
}



In conclusion, this is how RejectionHandler can be customized to handle errors in code. You can view the entire code on GitHub.

Thanks for reading! Happy coding!

This article was originally published on the Knoldus blog.

Further Reading

Error Handling Strategies

Akka (toolkit)

Published at DZone with permission of Praful Bangar. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Distributing Data and Logic: Enhancing Performance, Resilience, and Efficiency With Akka
  • All the Cloud’s a Stage and All the WebAssembly Modules Merely Actors
  • Writing a Chat With Akka
  • Video Streaming With Akka Streams

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook