Servicestack accessing json - servicestack

My Servicestack service is beeing posted Json (by jquery).
sendData = function(dataToSend) {
var request;
return request = $.ajax({
url: "/api/test",
type: "post",
data: JSON.stringify(dataToSend),
dataType: "json",
accept: "application/json",
contentType: "application/json"
});
The Json data is correctly deserialized if it corresponds to the root properties of my DTO (eg: userId:'foo' -> UserId=foo in the DTO).
I want to access the raw json posted data before it gets deserialized for adding custom deserialization.
Till now I had no problems accessing the querystrings with custom filters (RequestFilterAttribute) or if data vas posted like form.
Now I see the data that gets posted with Chrome Developer Tools is in the headers with "Request Payload" so it is nor in FormData and nor QueryString I can access when debugging my IHttpRequest.
How can I get my raw json data in the filter?

If you want to replace the default deserialization behavior with custom behavior for a specific request DTO, you can do this in your AppHost setup code:
JsConfig<MyRequestDtoClass>.DeSerializeFn = DeserializeMyRequestDto;
Where DeserializeMyRequestDto is a function or lambda taking a single string param - the raw request body - and returning the deserialized instance of your DTO:
MyRequestDtoClass DeserializeMyRequestDto(string rawBody) { ... }
RequestFilterAttribute subclasses purpotedly have access to the raw request body using request.GetRawBody(), where request is the IHttpRequest object passed into the filter's Execute method. But in my experience, GetRawBody returns an empty string, because the request input stream seems to be consumed by that time due to the deserialization. I worked around this once by creating an HTTP module (registered in AppHost via DynamicModuleUtility.RegisterModule) that would "peek" at the request input stream in a BeginRequest event handler. (The "peek" function would read the request input stream and then reset the Position of the stream to where it initially was.)

Related

How do i handle an api response with a header, response code, and body, using retrofit2?

I have an API that returns a response with a header, status code, and body field. How do I correctly handle this using retrofit, and Kotlin Coroutines? I'm used to a simple implementation such as below, but this does not work since the API is not just the JSON body.
Typical implementation:
interface MyApi {
#GET("myapi")
suspend fun getData() : DataClass
}
With the following response, the above implementation does not work:
{
statusCode=200.0,
headers={
x-custom-header=my custom header value
},
body={
"name":"John",
"message":"Hello"
}
}
Do I need to create a wrapper class for this new type of response? Then, to access the data just call WrapperClass.body? Or is there a more elegant solution to this?

How to get raw response data from axios request?

I am making a request to an API in which they sign their response body with a private key and send me the signature in a header. I am supposed to use their public key to validate the signature with the original response body but at the moment axios parses the response data there is something that is changing in it which makes the signature invalid. Is there some way to get the raw response data with axios?
I am doing a post request and want to get the string of the JSON object that axios automatically parses for me.
You can set a "identity" transformResponse.
let res = axios.get("url",
{ transformResponse: (r) => r }); //null transform (we do not want to parse as JSON);
//res.data should now contain a plain unparsed string
Not sure if setting transformResponse to null does the same thing as the identity transform.

Intercept sending request to change a header with request library

I am using the infamous request library to send requests.
One of those requests requires me to send the header multipart/mixed; boundary={myboundary}.
Request is using the form-data library for such requests but it does not set the Content-Type header properly. Therefore I would need to set it like this:
let req = request.post({url: "https://..."}, formData: formData)
req.setHeader('Content-Type', `multipart/mixed; boundary=${req.form().getBoundary()}`)
Sadly I can't add/alter any headers after firing the request. Therefore I want to know whether there is a way to intercept the sending so I can change the header?
You will need to use the multipart option instead of formData to use other, arbitrary multipart/* content types. Each object in the multipart array contains the headers to send in that part. The one exception is the body property which is used as the actual body of that part.
request.post({
url: 'https://...',
multipart: [
{ 'X-Foo-Header': 'bar', body: 'baz' },
// ...
],
headers: { 'Content-Type': 'multipart/mixed' }
});
The boundary should be automatically appended for an existing, explicit Content-Type header. This request test explicitly tests for this behavior.

Response encoding with node.js "request" module

I am trying to get data from the Bing search API, and since the existing libraries seem to be based on old discontinued APIs I though I'd try myself using the request library, which appears to be the most common library for this.
My code looks like
var SKEY = "myKey...." ,
ServiceRootURL = 'https://api.datamarket.azure.com/Bing/Search/v1/Composite';
function getBingData(query, top, skip, cb) {
var params = {
Sources: "'web'",
Query: "'"+query+"'",
'$format': "JSON",
'$top': top, '$skip': skip
},
req = request.get(ServiceRootURL).auth(SKEY, SKEY, false).qs(params);
request(req, cb)
}
getBingData("bookline.hu", 50, 0, someCallbackWhichParsesTheBody)
Bing returns some JSON and I can work with it sometimes but if the response body contains a large amount of non ASCII characters JSON.parse complains that the string is malformed. I tried switching to an ATOM content type, but there was no difference, the xml was invalid. Inspecting the response body as available in the request() callback actually shows bad code.
So I tried the same request with some python code, and that appears to work fine all the time. For reference:
r = requests.get(
'https://api.datamarket.azure.com/Bing/Search/v1/Composite?Sources=%27web%27&Query=%27sexy%20cosplay%20girls%27&$format=json',
auth=HTTPBasicAuth(SKEY,SKEY))
stuffWithResponse(r.json())
I am unable to reproduce the problem with smaller responses (e.g. limiting the number of results) and unable to identify a single result which causes the issue (by stepping up the offset).
My impression is that the response gets read in chunks, transcoded somehow and reassembled back in a bad way, which means the json/atom data becomes invalid if some multibyte character gets split, which happens on larger responses but not small ones.
Being new to node, I am not sure if there is something I should be doing (setting the encoding somewhere? Bing returns UTF-8, so this doesn't seem needed).
Anyone has any idea of what is going on?
FWIW, I'm on OSX 10.8, node is v0.8.20 installed via macports, request is v2.14.0 installed via npm.
i'm not sure about the request library but the default nodejs one works well for me. It also seems a lot easier to read than your library and does indeed come back in chunks.
http://nodejs.org/api/http.html#http_http_request_options_callback
or for https (like your req) http://nodejs.org/api/https.html#https_https_request_options_callback (the same really though)
For the options a little tip: use url parse
var url = require('url');
var params = '{}'
var dataURL = url.parse(ServiceRootURL);
var post_options = {
hostname: dataURL.hostname,
port: dataURL.port || 80,
path: dataURL.path,
method: 'GET',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': params.length
}
};
obviously params needs to be the data you want to send
I think your request authentication is incorrect. Authentication has to be provided before request.get.
See the documentation for request HTTP authentication. qs is an object that has to be passed to request options just like url and auth.
Also you are using same req for second request. You should know that request.get returns a stream for the GET of url given. Your next request using req will go wrong.
If you only need HTTPBasicAuth, this should also work
//remove req = request.get and subsequent request
request.get('http://some.server.com/', {
'auth': {
'user': 'username',
'pass': 'password',
'sendImmediately': false
}
},function (error, response, body) {
});
The callback argument gets 3 arguments. The first is an error when applicable (usually from the http.Client option not the http.ClientRequest object). The second is an http.ClientResponse object. The third is the response body String or Buffer.
The second object is the response stream. To use it you must use events 'data', 'end', 'error' and 'close'.
Be sure to use the arguments correctly.
You have to pass the option {json:true} to enable json parsing of the response

How to return only status code in POST request in servicestack Instead of HTML page

have created REST service using servicestack and in post request I have return object in following way
return new HttpResult(request)
{
StatusCode = HttpStatusCode.Created,
};
request: object which i have posted in database
When i check it in fiddler it render whole HTML Page of servicestack in response body, instead of that i would like to return Status code only, so please tell me how can i do?
Thanks
There was a bug in versions before < v3.05 that did not respect the HttpResult ContentType in some scenarios, it should be fixed now with the latest version of ServiceStack on NuGet or available from:
https://github.com/ServiceStack/ServiceStack/downloads
Prior to this you can still force the desired ContentType by changing the Accept:application/json Request Header on HttpClient or by appending ?format=json on the querystring of your url.
So now if you don't want to have any DTO serialized, you don't add it to the HttpResult:
return new HttpResult() { StatusCode = HttpStatusCode.Created };
Note you still might get an empty Html response back if calling this service in the browser (or any Rest Client that Accepts:text/html). You can force a ContentType that won't output any response if it has empty payload (e.g JSON/JSV) by specifying it in the result as well, e.g;
return new HttpResult() {
StatusCode = HttpStatusCode.Created,
ContentType = ContentType.Json
};

Resources