common validation logic error response and content negotiation

9 views
Skip to first unread message

Raghavan Chockalingam

unread,
Jun 24, 2016, 4:29:27 PM6/24/16
to spray.io User List
i have seen a few posts which touch around this area but i could not infer solution for my problems from those discussions.

i have a few url paths which exercise shared authentication or other validation logic. when authentication or validation fails, a text error message is sent back. the api supports custom media types, thus when a client requests for a specific media type for ex, 'vnd.myservice.v1+txt', a response is generated with appropriate content type when all auth or validation succeeds; if not, only 'text' error message is sent back. this does not work as spray-can i believe does try to enforce content negotiation and  informs client that only 'text/plain' is available as response content type. obviously, the authentication and validation directives would not have any knowledge of content-types to respond to. please advise on best practices to handle this situation. cheers.



object SprayTestApp extends App with SimpleRoutingApp {
   
implicit val system = ActorSystem("my-system")
    val mt
= MediaType.custom("application", "vnd.myservice.v1+txt")
    val mt2
= MediaType.custom("application", "vnd.myservice.v2+txt")


    startServer
(interface = "localhost", port = 8080) {
        path
("ping" / Segment) { password =>
           
get {
                auth
(password) {
                    respondWithMediaType
(mt) {
                        complete
("pong")
                   
}
               
}
           
}
       
} ~
          path
("hi" / Segment) { password =>
             
get {
                  auth
(password) {
                      respondWithMediaType
(mt2) {
                          complete
("hello")
                     
}
                 
}
             
}
         
}
   
}


   
def auth(password: String): Directive0 = {
       
if (password == "opendoors") pass
       
else complete("authError")
   
}


}


curl -v -H "Accept:application/vnd.myservice.v2+txt" localhost:8080/hi/opendoors -> returns hello
curl
-v -H "Accept:application/vnd.myservice.v2+txt" localhost:8080/hi/opendoor


> GET /hi/opendoor HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept:application/vnd.myservice.v2+txt
>
< HTTP/1.1 406 Not Acceptable
< Server: spray-can/1.3.3
< Date: Fri, 24 Jun 2016 20:24:03 GMT
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 104
<
Resource representation is only available with these Content-Types:
text
/plain; charset=UTF-8



Age Mooij

unread,
Jun 25, 2016, 1:32:26 PM6/25/16
to spray...@googlegroups.com
Hi Raghavan

It is true that the default rejection handler only produces plain text responses. But you can very easily customize the rejection handler since it is just a PartialFunction[List[Rejection], Route]. 
This means that you can either completely replace the default one or, probably better, wrap the default one in your own custom version.

An example:

The basic docs:

Hope this helps
Age


--
You received this message because you are subscribed to the Google Groups "spray.io User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to spray-user+...@googlegroups.com.
Visit this group at https://groups.google.com/group/spray-user.
To view this discussion on the web visit https://groups.google.com/d/msgid/spray-user/1b3541d5-92d4-4783-aaad-b3127d04deab%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Raghavan Chockalingam

unread,
Jun 28, 2016, 10:31:35 AM6/28/16
to spray.io User List
thanks Age. what i meant was, it is harder to write some common logic (auth, validation) to produce a response with media type requested in Accept header (ex: application/vnd.myservice.v2+txt). i eventually resorted to disabling content negotiation before sending a response for common logic in `text/plain`.

Age Mooij

unread,
Jun 28, 2016, 11:46:29 AM6/28/16
to spray...@googlegroups.com
I think you are confusing directives with responses. Most directives don't actually produce responses at all.

Certainly the authentication and validation directives don't produce responses at all. Instead, they filter requests, either rejecting them or letting them pass on to the next stage. 

For all happy paths, responses are eventually produced by one of the forms of the complete directive, which uses the media-type aware marshalling infrastructure to produce content negotiated responses. You have full control over this and everything is fully aware of content negotiation.

On the other hand, rejections that are not cancelled out by other directives can end up in the rejection handler, which will produce the actual error responses. It is the default rejection handler that produces error responses using the text/plain media type. That is the bit that breaks your content negotiation. 

So if you want your errors to use a certain media type, it's only the rejection handler that you need to customize. The examples that I linked to provide a way to deal with content negotiation specifically for those situations using a custom rejection handler.

Does that make sense?
Age



Reply all
Reply to author
Forward
0 new messages