I'm trying to use circe to do my JSON (de)serialization in an Akka-Http app, rather than spray-json. For that reason, I want to use the entity directive with as[String] to get the string representation of the request body, and then do my own deserialization. But it seems that entity is too smart for its own good, and is rejecting anything that does not have the Content-Type text/plain.
My understanding from the docs is that implicit magic should let me be able to do something like:
import akka.http.scaladsl.model.ContentTypes
entity(as[String].forContentTypes(ContentTypes.`application/json`))
But the compiler is not doing the whole thing of inferring that I want as to resolve to a FromEntityUnmarshaller[String], which has that implicit method forContentTypes, whose result should be converted to a FromMessageUnmarshaller[String], which (due to contravariance) should satisfy the need for a FromRequestUnmarshaller[String].
However, even holding the compilers hand by doing:
val jsonRequestToStringUnmarshaller: FromRequestUnmarshaller[String] =
messageUnmarshallerFromEntityUnmarshaller(implicitly[FromEntityUnmarshaller[String]].forContentTypes(ContentTypes.`application/json`))
entity(jsonRequestToStringUnmarshaller)
my server is still rejecting application/json requests.
What gives?
Update
I can see now that I misunderstood forContentTypes, and that it will only narrow, not expand, the Content-Type range that an Unmarshaller will accept. That just explains why my solution isn't working.
I would suggest to give Akka-Http direct marshallers-unmarshallers from / to desired types using circe under the hood.
It may look like: https://github.com/PDXostc/rvi_sota_server/blob/master/common/src/main/scala/org/genivi/sota/marshalling/CirceMarshallingSupport.scala
Related
I have $dinetype variable obtained from the user.
But I would like to give response based on what value has been set in $dinetype variable. In addition to giving responses, I also need to set relevant context. How do I do this in DialogFlow?
if($Dinetype=='dineout')
ask ('which restaurant would you like to go to?')
set_context ('awaiting-restaurant')
if($Dinetype=='takeaway')
ask ('When would you like to take away?')
set_context ('awaiting-takeaway-time')
Is it programmable at all? Or is it possible to achieve something equivalent to the above in the UI?
Edit: A much easier way has been added to handle this issue directly in Dialogflow
(Updated Solution) Follow-up Intents:
After creating an intent, you can add follow-up intents now.
Intents -> Create Intent >
[Response=Prompt For Conditional Response]
Intents -> Add Follow-up Intent -> Custom/Yes/No
Then set the training praise to a matching entity you want to conditionally respond to
OLD HACKY SOLUTION:
Late reply, but maybe someone will find this useful.
If the conditional response only needs to reference a single parameter
value, then I figured out what you can do is utilize the Entity's
"Reference Value" as the response you want to give for a particular
set of Synonyms.
So you'd have an entity that looked like this:
Then, setup your intent like this, with a response of $Dinetype:
Then the end result will look like this:
And you can make whatever follow-up intent you need from there.
Down-side is Dinetype won't be as reusable. But I still think it
beats writing a fulfillment webhook every time you need a simple
conditional response.
You can't do this in the Response section directly. The Response section is meant for fairly simple responses that don't require significant logic to process. Although you can use parameters in the response, you can't give a different response based on the value of the parameter. So you can set a response to something like
I think $Dinetype is great food.
but not
{{#if $Dinetype == "Thai"}}I think Thai food is too hot{{/if}}
or anything like that
However, you can add code that sends conditional responses and contexts by implementing a Fulfillment webhook. Although you can't do this for each Intent as part of the Intent editor screen, the Fulfillment screen includes a built-in code editor.
I found a solution to my similar problem using composite entities, which may or may not be overkill for your agent. The value assigned to a parameter associated with the (composite) entity will contain a JSON structure, if a synonym in that entity was matched.
Using the "Dot" notation, you can assign the matched sub-entity's property (similar to the reference value of a normal entity) to another parameter in the Actions and Parameters section. You can have one parameter for each sub-entity and hence, you can evaluate these parameters in your response section to select each response variants:
$Parameter_A ResponseA
$Parameter_B ResonseB
....
etc.
Clunky but works. Just have to be careful to reference the property exactly as it is defined in the composite entity.
Given a REST api.
I want to learn what media types I can set in the Accept header.
How should I this?
I know I could do a random
GET http://some.api.com/
Accept:flying/elephants
and hope for a 406 with a body that has the correct acceptable media types.
Is there a better way?
In theory, API could indicate supported Content Types via HTTP OPTIONS
Usually, API offers either
Documentation
Specific resource of supported Accept-header values.
Also (as you might know), Accept-header values are usually bound to IANA defined MIME types
One issue with this is any URI within the API can respond with different media types. It's very common to have different endpoints in the API return different content types.
You could use multiple wildcard requests to probe for support.
You can start with Accept: */* and then application/* text/* */json */xml etc. You would receive a non-exhaustive list, but you'd get the big ones and the the preferred ones.
There's other weird edge cases. For example OData allows you to specify a $format parameter in the URL to define the response type. This overrides the accept header. Thus every format is it's own URI.
It'd be cool if APIs made more use of the alternate link relationship (http://www.w3.org/TR/html5/links.html#rel-alternate), i think that would be the most appropriate. That combined with the type attribute of the link would let you know all the formats for any resource you retrieve. Again it would be specific to each URI though.
Usually to retrieve a resource one uses:
GET http://ws.mydomain.com/resource/123212
But what if your item IDs are HTTP URIs?:
GET http://ws.mydomain.com/resource/http://id.someotherdomain.com/SGX.3211
Browsers replace two slashes with one, and the request turns into:
GET http://ws.mydomain.com/resource/http:/id.someotherdomain.com/SGX.3211
which will not work.
URI encoding the "http://id.someotherdomain.com/SGX.3211" -part results in HTTP 400 - Bad request.
Is there a best practice for handling this?
Edit:
Then of course if we would need to have (I don't at the moment) request in form:
resources/ID/collections/ID
and all IDs are HTTP URIs, things get out of hand... Possibly one could do something like this and parse the contents inside the curly braces:
resources/{http://id...}/collections/{http://id...}
Encode the other system's URI, and then pass the value as a query parameter:
GET http://ws.mydomain.com/resource?ref=http%3A%2F%2Fid.someotherdomain.com%2FSGX.3211
Ugly looking, but no one said that URIs used in a REST architecture have to be beautiful. :)
By the way, a GET actually looks like this when it's sent:
GET /resource?ref=http%3A%2F%2Fid.someotherdomain.com%2FSGX.3211 HTTP/1.1
Host: ws.mydomain.com
UPDATE: apparently you no longer have to encode "/" and "?" within a query component. From RFC 3986:
The characters slash ("/") and question mark ("?") may represent data
within the query component. Beware that some older, erroneous
implementations may not handle such data correctly when it is used as
the base URI for relative references (Section 5.1), apparently
because they fail to distinguish query data from path data when
looking for hierarchical separators. However, as query components are
often used to carry identifying information in the form of "key=value"
pairs and one frequently used value is a reference to another URI, it
is sometimes better for usability to avoid percent-encoding those
characters.
So you could legally do this:
GET /resource?ref=id.someotherdomain.com/SGX.3211 HTTP/1.1
Host: ws.mydomain.com
I'm developing a RESTful API service which initially will only be accepting and responding in JSON format. I want to follow standards and in case of requester's Accept header was different than JSON I want to respond with 406 HTTP status code to inform the requester I cannot output data in other format.
According to W3 I "SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate" in my response.
How do I do that, because the above explanation doesn't tell me much. What is the mentioned entity?
Any ideas/suggestions?
EDIT
Initially I thought that maybe could be a comma separated list in Content-Type header but after rethinking maybe I should do the same thing browsers do and use Accept header? This makes much more sense actually, but I cannot find any information to support this.
Three issues here:
First, the note from RFC 2616 is meant to address URI schemes where responses of different types are made available at various URI's, such as "/path/to/thing.xml" vs "/path/to/thing.json". That's not always a popular choice, but if you can do that, do so and include hyperlinks to each one in the "entity"; that is, in the body of the response. Since the RFC doesn't mandate a Content-Type or processing model for such links, you're on your own regarding how to return them, but HTML with <a> tags is common and useful.
If you don't want to expose multiple types at separate URI's, but just want to expose one type at the original URI, then it's perfectly fine to respond with 406 and an entity that simply says which types the resource can emit.
Second, note that most web browsers send */* in the Accept header (with a low quality value), which should match any Content-Type. In addition, the spec says "...if no Accept header field is present, then it is assumed that the client accepts all media types." So the cases where you should be raising 406 are rare.
Third, don't emit a Content-Type response header that is anything other than the Content-Type of the response entity. It should not be used to list acceptable types. You should also not emit a response header named 'Accept'; the 'Accept' header is for requests only; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
I have a resource at a URL that both humans and machines should be able to read:
http://example.com/foo-collection/foo001
What is the best way to distinguish between human browsers and machines, and return either HTML or a domain-specific XML response?
(1) The Accept type field in the request?
(2) An additional bit of URL? eg:
http://example.com/foo-collection/foo001 -> returns HTML
http://example.com/foo-collection/foo001?xml -> returns, er, XML
I do not wish to oblige machines reading the resource to parse HTML (or XHTML for that matter). Machines like the googlebot should receive the HTML response.
It is reasonable to assume I control the machine readers.
If this is under your control, rather than adding a query parameter why not add a file extension:
http://example.com/foo-collection/foo001.html - return HTML
http://example.com/foo-collection/foo001.xml - return XML
Apart from anything else, that means if someone fetches it with wget or saves it from their browser, it'll have an appropriate filename without any fuss.
My preference is to make it a first-class part of the URI. This is debatable, since there are -- in a sense -- multiple URI's for the same resource. And is "format" really part of the URI?
http://example.com/foo-collection/html/foo001
http://example.com/foo-collection/xml/foo001
These are very easy deal with in a web framework that has URI parsing to direct the request to the proper application.
If this is indeed the same resource with two different representations, the HTTP invites you to use the Accept-header as you suggest. This is probably a very reliable way to distinguish between the two different scenarios. You can be plenty sure that user agents (including search engine spiders) send the Accept-header properly.
About the machine agents you are going to give XML; are they under your control? In that case you can be doubly sure that Accept will work. If they do not set this header properly, you can give XML as default. User agents DO set the header properly.
I would try to use the Accept heder for this, because this is exactly what the Accept header is there for.
The problem with having two different URLs is that is is not automatically apparent that these two represent the same underlying resource. This can be bad if a user finds an URL in one program, which renders HTML, and pastes it in the other, which needs XML. At this point a smart user could probably change the URL appropriately, but this is just a source of error that you don't need.
I would say adding a Query String parameter is your best bet. The only way to automatically detect whether your client is a browser(human) or application would be to read the User-Agent string from the HTTP Request. But this is easily set by any application to mimic a browser, you're not guaranteed that this is going to work.