Default Content Type + Deserialization errors - servicestack

I have configured my AppHost with JSON as the default content type. Unfortunately in situations when ServiceStack fails to deserialize the request into the corresponding DTO it responds with an application/xml content. Here's an example response (I've omitted most of the message and stacktrace element values for brevity):
<UpsertResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="">
<ResponseStatus>
<ErrorCode>SerializationException</ErrorCode>
<Message>Could not deserialize 'application/xml' request using ...</Message>
<StackTrace>at ServiceStack.WebHost.Endpoints.Support.EndpointHandlerBase.CreateContentTypeRequest(IHttpRequest httpReq, Type requestType, String contentType)...</StackTrace>
</ResponseStatus>
</UpsertResponse>
I guess the response is encoded that way because the request was sending 'application/xml' content. Is there a way to force (or hook into) ServiceStack to use the default content type?
A bit more conext - not only does my service uses JSON as the default content type, but it (tries to) ensures that JSON is the only accepted content type via a global request filter, which checks Accept/Content-type headers during each read/write and short-circuits the request with a 400 response when the content type is not 'application/json'.

Related

Scrapy - is it possible to extract Payload Request from Response

is it possible to extract and set as variable the "Payload Request" which has been pushed in order to receive particular response?
You can access the request object in the callback function by response.request.
This object is the request object itself, so it contains everything you passed in the request. It doesn't have a "payload" attribute though.
The equivalent should be response.request.body, assuming you had a body in the request. Everything else is still there, headers, cookies, meta, method, etc
More on the params of request here.

RAML MimeType for text/plain

Am trying to send a application/flatfile . (fixed width format) file in response back to consumer. how do i specify that in RAML 1.0
am trying to provide mime type for RAML which will be used in mulesoft . am building application/flatfile in dataweave 2.0 and want to send that back in response as an attachment. what mime type should i choose in body ? and for the consumer can he download the file , i see postman can do that while invoking (send and download)
who ever consume this should be able to get response as a file attachment and how do i mention the properties in raml for application/flatfile
/test:
/sfdc:
/time:
get:
is: [client-id-required]
responses:
200:
body:
text/plain:
The mime type of the response should be whatever the type of content being downloaded is.
In cases where the response's content type may vary, say the server may respond with a plain text, pdf or an octet stream, then the raml should look something like this:
responses:
200:
body:
text/plain:
application/pdf:
application/octet-stream:
And in addition to the Content-Type header, the http response should also have a Content-Disposition header with a value of "attachment".
Something like the following:
Content-Type: text/plain
Content-Disposition: attachment; filename="my_flat_file.txt"

Why is the request body blank when the content-type is application/x-www-form-urlencoded?

I am receiving a request with content-type application/x-www-form-urlencoded. When I try to read the body of the request using cherrypy.request.body.read() the results is b''.
I seem to be able to access the request form parameters using any of these:
cherrypy.request.params
cherrypy.request.body.params
cherrypy.request.body.request_params
But this is inconvenient for my use case, I want to be able to obtain the raw request body regardless of content-type. Also the above 3 give me a dictionary, which isn't the exact format that the request had in its body. Is there a way to do that with cherrypy? Or is this functionality hidden?
Not sure what are you trying to accomplish by not using the already parsed body that correspond to the defined Content-Type... but you can process the body of the request yourself configuring: cherrypy.request.process_request_body = False and read the body with something like:
cherrypy.request.rfile.read(cherrypy.request.headers['Content-Length'])
For more information see: https://github.com/cherrypy/cherrypy/blob/master/cherrypy/_cprequest.py#L292-L315
Fragment of relevant parts of that url:
rfile = None
"""
If the request included an entity (body), it will be available
as a stream in this attribute. However, the rfile will normally
be read for you between the 'before_request_body' hook and the
'before_handler' hook, and the resulting string is placed into
either request.params or the request.body attribute.
You may disable the automatic consumption of the rfile by setting
request.process_request_body to False, either in config for the desired
path, or in an 'on_start_resource' or 'before_request_body' hook.
WARNING: In almost every case, you should not attempt to read from the
rfile stream after CherryPy's automatic mechanism has read it. If you
turn off the automatic parsing of rfile, you should read exactly the
number of bytes specified in request.headers['Content-Length'].
Ignoring either of these warnings may result in a hung request thread
or in corruption of the next (pipelined) request.
"""
process_request_body = True
"""
If True, the rfile (if any) is automatically read and parsed,
and the result placed into request.params or request.body.
"""
body = None
"""
If the request Content-Type is 'application/x-www-form-urlencoded'
or multipart, this will be None. Otherwise, this will be an instance
of :class:`RequestBody<cherrypy._cpreqbody.RequestBody>` (which you
can .read()); this value is set between the 'before_request_body' and
'before_handler' hooks (assuming that process_request_body is True."""

Cannot map content-type header using int-http:outbound-gateway

I have an http:inbound-gateway, receive a json message, do some enrichment and send it to an endpoint using an http:outbound-gateway to call a rest service also with json payload.
Inbound-gw receives the content-type header, it is set on the message header but when the payload is sent to the rest service using the outbound-gw the following error happens: 415 Unsupported Media Type
I checked the log and the following warning shows up:
WARN DefaultHttpHeaderMapper:951 - Header 'content-type' with value 'application/json' will not be set since it is not a String and no Converter is available. Consider registering a Converter with ConversionService (e.g., )
It's strange because the content-type header is set with value application/json and I use the mapped-request-headers="HTTP_REQUEST_HEADERS". I'm using SI 4.3.1.RELEASE, any idea?
Here's the http:inbound-gw
<int-http:inbound-gateway id="restHttpInboundGateway"
request-channel="restHttpInboundChannel" path="/services"
supported-methods="GET,POST,PUT,DELETE,PATCH,HEAD"
reply-channel="restHttpOutboundChannel"
mapped-request-headers="http_requestMethod,Content-Length,Accept,Connection, Content-Type">
<int-http:request-mapping consumes="application/json,application/xml"
produces="application/json,application/xml" />
</int-http:inbound-gateway>
and here's the outbound-gw
<int-http:outbound-gateway id="restHttpOutboundGateway"
request-channel="restHttpOutboundGatewayChannel" reply-channel="restHttpOutboundChannel"
url-expression="https://localhost:8443/service/rest/contacts/1" mapped-request-headers="HTTP_REQUEST_HEADERS"
http-method-expression="PUT" expected-response-type="java.lang.String"
charset="UTF-8"/>
Here's the message logged before the outbound-gw:
2016-10-08 10:07:04,634 INFO serviceMessages:194 - GenericMessage [payload=byte[76], headers={content-length=76, replyChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#44237f19, errorChannel=org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#44237f19, content-type=application/json, connection=keep-alive, id=79012bea-263b-0f48-6e96-5fc832c08da6, accept=[text/plain, /], timestamp=1475932024630}]
This looks like a bug; the header mapper is supposed to always map Content-Type to/from contentType in Spring Integration messages. The outbound adapter is expecting contentType.
However, the code that does that on the inbound side is looking for Content-Type (case-sensitive) and is getting content-type from Spring MVC. Perhaps something has changed.
It looks like we need to make this mapping test case-insensitive.
In the meantime, you can add a header enricher to copy the header...
<header-enricher ...>
<header name="contentType" expression="headers['content-type']" />
</header-enricher>
and a header-filter to remove the content-type header (to eliminate the warning log).
There is another bug in the DefaultHttpHeaderMapper, when it isn't supplied with the ConversionService, therefore MimeType for your content-type header can't be converted to String.
You can create DefaultHttpHeaderMapper.outboundMapper() bean instead of mapped-request-headers for the <int-http:outbound-gateway>. Or, again: re-map content-type to itself:
<header name="content-type" expression="headers['content-type'].toString()" override="true"/>

Spring Integration HttpRequestExecutingMessageHandler with url parameter expressions

I have a HttpRequestExecutingMessageHandler which should make HTTP GET requests to an endpoint URI and, for each request, it should pass two URL parameters with values obtained from the flowing message's headers. How can I get a Message's header values and apply them to each request made via the HttpRequestExecutingMessageHandler?
So far I have tried configuring my handler as follows:
SpelExpressionParser expressionParser = new SpelExpressionParser();
Map<String, Expression> uriVariableExpressions = new HashMap<String, Expression>(2);
uriVariableExpressions.put("userId", expressionParser.parseExpression("headers.userId"));
uriVariableExpressions.put("roleId", expressionParser.parseExpression("headers.roleId"));
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler(uri);
handler.setHttpMethod(HttpMethod.GET);
handler.setUriVariableExpressions(uriVariableExpressions);
but, when a message flows through and the HTTP request is made, the Message's userId and roleId header values are not set as parameters in the request's URL. When debugging, I can see that the Message's headers and values are definitely in the flowing Messages. Is the spel expression correct?
Thanks,
PM
Your uri has to have placeholders to substitute your variables, e.g.:
http://foo.com/service?userId={userId}&roleId={roleId}
From other side, show, please, your uri and the logs, when you send a message.

Resources