Spray 1.2 ignores content-type header in response - spray

I am trying to set application/json as content-Type in a spray-routing actor. But the content-type i see in my response always is text/plain. I tried using the spray-routing approach ("something") and the spray-can approacch ("something2") but the two routes don't send the response-type properly. Did I miss something?
def receive = runRoute {
path("something") {
get {
respondWithHeader(`Content-Type`(`application/json`)) {
complete("""{ "key": "value" }""")
}
}
} ~
path("something2") {
get {
complete(HttpResponse(entity = """{ "key": "value" }""").withHeaders((List(`Content-Type`(`application/json`)))))
}
}
}`enter code here`

It seems that the responseheader is overwritten by the marshaller for string.
Like this it works like a charm:
path("something") {
get {
respondWithMediaType(`application/json`) {
complete("""{ "key": "value" }""")
}
}
}

Actually, there is a much better approach to return a json with a application/json content type with spray.json module. If you have just key:value pairs it would be much cleaner to use SprayJsonMarshaller, which would authomatically set appropriate header. Consider the following example:
(get & path("somePath")) { complete(Map("key" -> "value")) }
To make a json response you just need to import two things:
import spray.json.DefaultJsonProtocol._ // contains default marshallers
import spray.httpx.SprayJsonSupport._ // will do all the headers work
If you have your own case class which you would like to send over the wire, then provide a converter into json format:
import spray.json.DefaultJsonProtocol._
case class SomeClass(name: String)
object SomeClass {
implicit val someClassJson = jsonFormat1(SomeClass.apply)
}
It's a much better approach cause if you later would like to change the format in you response, all you need to do is to change a marshaller, the rewrite your code.
number in the end of jsonFormat method equals to the number of case class arguments.

Related

Default format for withFormat in Grails 3.x

In Grails this could be use for content negotiation, especially useful to implement APIs:
withFormat {
xml { ... some code that renders XML }
json { ... some code that renders JSON }
}
Now, if I need a default format, let's say JSON, the "... some code that renders JSON" should be executed twice, once for the JSON option and once for the "*" option that is, AFAIK the "any other matching format", which is a way to specify the default format, like:
withFormat {
xml { ... some code that renders XML }
json { ... some code that renders JSON }
"*" { ... some code that renders JSON }
}
My questions are:
Is that the correct way of specifying the default format as JSON?
Is there a way of not repeating the same code for two options? (I mean something like: json, "*" { ... }
Instead of this...
withFormat {
xml { ... some code that renders XML }
json { ... some code that renders JSON }
"*" { ... some code that renders JSON }
}
Use this:
withFormat {
xml { ... some code that renders XML }
"*" { ... some code that renders JSON }
}
The one problem with this is that it is highly redundant and would have to be done in EVERY CONTROLLER METHOD. Would suggest moving this functionality to HandlerInterceptor or using something like Beapi API Framework plugin

Convert string JSON response to a boolean using Swift 4 Decodable

I'm refactoring some projects where I'd previously used third-party JSON parsers and I've encountered a goofy site that returns a boolean as a string.
This is the relevant snippet from the JSON response:
{
"delay": "false",
/* a bunch of other keys*/
}
My struct for Decoding looks like this:
struct MyJSONStruct: Decodable {
let delay: Bool
// the rest of the keys
}
How would I convert the string returned in the JSON response into a Bool to match my struct in Swift 4? While this post was helpful, I can't figure out how to turn a string response into a boolean value.
Basically you have to write a custom initializer but if there are many good keys but only one to map from a type to another a computed property might be useful
struct MyJSONStruct: Decodable {
var delay: String
// the rest of the keys
var boolDelay : Bool {
get { return delay == "true" }
set { delay = newValue ? "true" : "false" }
}
}
you need to set the boolEncoding: .literal in the URLEncoding initializer.
boolEncoding: .literal

Can I have another form of an enum value?

I have an enum in client code describing a list of endpoints in the API:
enum Requests {
GetUsers,
GetProducts,
...
}
I want to send requests to server having these values, like connection.sendRequest(Requests.GetUsers).
Now, in the sendRequest() function I want the enum value to be converted to something like '/users'.
Can I attach methods to each enum similar to this below?
enum Requests {
GetUsers.toString: '/users',
GetPendingDomains: '/prodcuts'
}
Not directly in the enum (enums are really basic in Dart). You have to create a Map<Requests, String> aside to handle the associated paths.
enum Request { GetUsers, GetProducts, ... }
final paths = <Request, String>{
Request.GetUsers: '/users',
Request.GetProducts: '/products',
}

Spray Returning JSON

I've just started using Spray and I'm building a sample API that simply returns some JSON.
Take the following example. I have the alphabet stored in a singleton...
class Alphabet {}
object Alphabet {
final val alphabet = Array('a', 'b', 'c', ...)
}
I then have a simple spray route...
path("list") {
get {
respondWithMediaType(`application/json`) {
complete(Alphabet.alphabet)
}
}
}
This works fine and seems to return an "application/json" response with the correct data. But is this valid? i.e. is this a correctly formatted response that would be expected by an end user?
The reason I ask is I have looked at a number of Spray examples and most seem to use case classes and specify custom JSON formatters similar to this...
object CustomJsonProtocol extends DefaultJsonProtocol {
implicit val responseFormat = jsonFormat3(CaseClassHere)
}
...
complete {
CaseClassHere("Test", "Test");
}
Whats the correct approach?
Thanks

Can non-trivial constructors call Future returning functions (how or alternatives)

Suppose you have:
class Schema {
Schema.fromText(String jsonString) {
...
}
}
In this constructor, assume there is an URL provided in the jsonString to download data and the only API to read an URL is one that returns a Future. Also, assume Schema is only a valid object when that URL data has been read and processed. Is it possible to even implement ...?
What you want to do is not possible with standard constructors.
Instead, try a static method that returns a new instance wrapped in a Future.
Something like:
class Schema {
Schema._fromApi(String apiResults) { ... }
static Future<Schema> build(String jsonString) {
return getContentsOfUrl(jsonString['url'])
.then((contents) => new Schema._fromApi(contents));
}
}

Resources