How to send 206 status code when using active_model_serializer gem and Rails API and will_paginate/kaminari - active-model-serializers

I'm using AMS, Rails 5.2.2 API with will_paginate gem. It works as needed but the response code is 200 instead of 206
#adsresses_controller
def index
#addresses = Address.all.paginate(page: params[:page], per_page: 25)
json_response(#addresses, :ok, include: ['shop', 'shop.country'])
end
where json_response is just a method defined in controllers/concerns/response.rb:
module Response
extend ActiveSupport::Concern
def json_response(object, status = :ok, opts = {})
response = {json: object, status: status}.merge(opts)
render response
end
...
end
The question is what is the best rule to send the correct response, - 200 or 206 in case of the paginated response ?
Thank you.

https://guides.rubyonrails.org/layouts_and_rendering.html
2.2.12.4 The :status Option Rails will automatically generate a response with the correct HTTP status code (in most cases, this is 200
OK). You can use the :status option to change this:
render status: 500
render status: :forbidden
Your response code is
200
because you ask for it with :ok.
You should work around that with something like :
json_response(#addresses, 206, include: ['shop', 'shop.country'])
or
json_response(#addresses, :partial_content, include: ['shop', 'shop.country'])
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206
The HTTP 206 Partial Content success status response code indicates
that the request has succeeded and has the body contains the requested
ranges of data, as described in the Range header of the request.
So mostly depend on your application I think.

The solution I came to was to add a helper method to controllers/concerns/response.rb to be able to return the right status for paginated response:
def paginated_response_status(collection)
collection.size > WillPaginate.per_page ? :partial_content : :ok
end
and use it in AdressesController actions when needed:
#controllers/api/addresses_controller.rb
def index
#addresses = Address.all
paginate(
json: #addresses,
include: ['shop', 'shop.country'],
status: paginated_response_status(#addresses)
)
end
The above example was for will_paginate gem and api-pagination gem.
Hope this helps.

Related

Uploading an image using Multipart by karate API tool [duplicate]

I have a simple POST request that requires a json Content-Type header and a body like
{
oneNbr: "2016004444",
twoCode: "###",
threeNbr: "STD PACK",
sheetTitle: "010000",
codeType: "AF14"
}
When I run this in Postman, it runs as expected, returning 200 status and the expected response.
Here's the same script in Karate:
Scenario: Sample test
* def payload =
"""
{
oneNbr: "2016004444",
twoCode: "###",
threeNbr: "STD PACK",
sheetTitle: "010000",
codeType: "AF14"
}
"""
Given path '/my_end_point/endpoint'
And request payload
When method post
Then status 200
When I run this, it returns {"code":"415","status":"Unsupported Media Type"}. The console output shows that the right content-type is being set during the POST.
Even if I specifically set the content-type in the script, 415 is still returned e.g.
And header Content-Type = 'application/json'
OR
* configure headers = { 'Content-Type': 'application/json' }
Any help is appreciated.
We did some debugging and found that Karate automatically appends 'charset=UTF-8' to the Content-Type header. The API does not expect charset.
Found the following post and that solved the problem:
How can I send just 'application/json' as the content-type header with Karate?
Posting this to help others in future.
It's simple. Try to use this in your background.
* def charset = null
Try adding a * header Accept = 'application/json' header. The one difference between Karate and Postman is that Postman tries to be smart and auto-adds an Accept header - whereas Karate does not.

completely failed to read post data in vertx route handler chain - tried all ways no success

i'm running a gradle build with vertx web. my library dependecies include
// for mock API serving https://mvnrepository.com/artifact/io.vertx/vertx-core
compile group: 'io.vertx', name: 'vertx-core', version: '3.5.3'
compile group: 'io.vertx', name: 'vertx-web', version: '3.5.3'
so in my groovy script code i do this
Vertx vertx = Vertx.vertx()
HttpServer server = vertx.createHttpServer()
...
I then declare a route to catch all requests on resource and process the request and form a response - trying to keep it simple - just return simple string as response
Router allRouter = Router.router(vertx)
allRouter.route ( "/api/now/table/incident")
.handler(BodyHandler.create())
.blockingHandler { routingContext ->
def request = routingContext.request()
HttpMethod method = request.method()
def response = routingContext.response()
response.putHeader ("content-type", "text/plain")
def uri = routingContext.request().absoluteURI()
switch (method) {
case HttpMethod.GET:
println "processing a resource GET on uri : $uri "
response.end ("(GET) howdi will")
break
case HttpMethod.POST:
String bodyEnc = routingContext.getBodyAsJson().encodePrettily()
println "processing a resource POST on uri : $uri"
println "post request received post data : " + bodyEnc
response.end ("(POST) howdi will")
break
}
}
I create a handler for BodyHandling, before the general handler in the route.
Then I start the server with the route
server.requestHandler(allRouter.&accept)
server.listen(8081, "localhost")
works all fine for a get request from postman.
when i use a post request with a request body data - the service hangs and i have to cancel - it never gets to the switch statement. All that happens in the console when i issue the post is
23:30:16.455 [vert.x-eventloop-thread-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 32768
23:30:16.455 [vert.x-eventloop-thread-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxSharedCapacityFactor: 2
23:30:16.455 [vert.x-eventloop-thread-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.linkCapacity: 16
23:30:16.455 [vert.x-eventloop-thread-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
23:30:16.478 [vert.x-eventloop-thread-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.bytebuf.checkAccessible: true
23:30:16.482 [vert.x-eventloop-thread-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector#51d486
This is the nearest to being a related topic enter link description here
I have tried this countless ways now, set bodyHandler inside the request when i get it etc - can't get it to work.
my postman post looks like this - where the headers are set to Content-Type application/json, Content-Length is 296 bytes (length of bytes in utf16), and Accept is text/plain to receive simple response
The documentation is just not clear. Blown 12 hours trying to crack this.
Does any one know exactly how one should get the post data on a request when using vertx web please
It appears as though my problem was the size of bytes being sent. I had calculated the bytes of the reqBody string as 296 bytes (using UTF16 charset), and set this into the Postman request.
So the vertx server was trying to read that many when processing the body and hanged. When I just did reqBody.getBytes().size - effectively UTF8, this returned 147 bytes. When I changed the content-length to this in postman, it started to work.
There is a timing issue in where you setup the BodyHandler. I tried this is tin the switch case, and it fails with request has already been read.
However neither of these seem to work successfully.
option 1 : ' create body handler before the route (path) call'
allRouter.route().handler(BodyHandler.create())
//now try and setup the route for API path interception
allRouter.route ( "/api/now/table/incident")
.blockingHandler { routingContext -> ...
option 2 : 'chain the handlers but put the Body Handler first'
//now try and setup the route for API path interception, followed by body handler
allRouter.route ( "/api/now/table/incident")
.handler(BodyHandler.create())
.blockingHandler { routingContext ->...
This was setting the content-length, assuming UTF16 for internal byte size that was the real problem. Now back to trying to complete what I set out to do.

Video seeking in Google Chrome: How to handle continuous Partial Content requests?

This question may be a little overwhelming, but I feel close to understanding the way video seeking works in Google Chrome, but it's still very confusing to me and support is difficult to find.
If I am not mistaken, Chrome initially sends a request header with Range bytes=0- to test if the server understands Partial Content requests, and expects the server to respond with status code 206.
I have read the following answers to get a better understanding:
Need more rep to link them, their topics are:
can't seek html5 video or audio in chrome
HTML5 video will not loop
HTTP Range header
My server is powered by Node.js and I am having trouble with getting continuous range requests out of chrome during playback. When a video is requested, the server receives a bytes=0-, the server then responds with status code 206 and
then the media player breaks.
My confusion is with with the response header, because I am not sure how to
construct my response header and handle eventual range requests:
Do I respond with a status code 200 or 206 initially?
When I respond with 206 I only receive bytes=0-, but when I respond with
200 I receive bytes=0- and after that bytes=355856504-.
If I were to subtract 355856504 of the total Content-Length of the video file, the result is 58, and bytes=0-58 seems like a valid Content-Range?
But after those two requests, I receive no more range requests from Chrome.
I am also unsure if the Content-Range in the response header should looks like "bytes=0-58" or like "bytes=0-58/355856562" for example.
Here is the code
if(req.headers.range) console.info(req.headers.range); // prints bytes=0-
const type = rc.sync(media, 0, 32); // determines mime type
const size = fs.statSync(media)["size"]; // determines content length
// String range, initially "bytes=0-" according to Chrome
var Strange = req.headers.range;
res.set({
"Accept-Ranges": "bytes",
"Content-Type": ft(type).mime,
"Content-Length": size-Strange.replace(/bytes=/, "").split("-")[0],
"Content-Range": Strange+size+"/"+size
});
//res.status(206); // one request from chrome, then breaks
res.status(200); // two requests from chrome, then breaks
// this prints 35585604-58, whereas i expect something like 0-58
console.log("should serve range: "+
parseInt(Strange.replace(/bytes=/, "").split("-")[0]) +"-"+
parseInt(size-Strange.replace(/bytes=/, "").split("-")[0])
);
// this function reads some bytes from 'media', and then streams it:
fs.createReadStream(media, {
start: 0,
end: parseInt(size-Strange.replace(/bytes=/, "").split("-")[0]) // 58
}).pipe(res);
Screenshots of the request and response headers when status code is 200:
first response and request headers
second response and request headers
Screenshot of the request and response header when status code is 206:
Need more rep, to show another screenshot
Essentially the request is:
"Range: bytes=0-"
and the Content-Range response is:
"bytes=0-355856562/355856562"
One apparent error is that you are returning an invalid value in the Range header. See the sepcification - it should be 0-355856561/355856562 since the second value after the dash is the last byte position not length.

Changing status code changes response body in Express

So I have a pretty simple helper function to send errors in my response. I use this function all over my codebase:
exports.error = function (err, res) {
res.send({
success: false,
errorMsg: err.message,
errors: err.errors == null ? [] : err.errors
});
};
I decided to add a status code to it:
exports.error = function (err, res, status) {
res.status(status).send({
success: false,
errorMsg: err.message,
errors: err.errors == null ? [] : err.errors
});
};
If the status is 200 I get the body exactly like the object passed to the send method. The problem is that if status is different from 200 (400 or 500 for example) my response body changes to:
{
config: Object
data: Object
headers: function (d)
status: 500
statusText: "Internal Server Error"
}
And my original response body (the one with success, errorMsg and errors fields) is inside this new response under the data attribute. I have no idea why this is happening but as far as I know I don't have any other custom error handlers in my application. I don't want this behavior and instead I want only my original response body.
I am using the body-parser package, but I believe that it only affects the requests, not the responses.
The response object that you're getting is Angular's response object (see the documentation):
The response object has these properties:
data – {string|Object} – The response body transformed with the transform functions.
status – {number} – HTTP status code of the response.
headers – {function([headerName])} – Header getter function.
config – {Object} – The configuration object that was used to generate the request.
statusText – {string} – HTTP status text of the response.
AFAIK, when Angular receives a successful HTTP response (like a 200), it will run any of the default transformations to convert the response to, say, a JS object (from a JSON response).
However, it won't do that when the HTTP response indicates an error. In that case, you will get the above-mentioned response object back.
Thanks to #robertklep I found out that the problem was actually in my Angular code that handled errors. Instead of returning the response body my Angular error handler was returning the error itself.

Get the response headers from redirect url using node.js

Objective:
Te get the response.headers when I get the status code as 302 from redirects uri response
Issue:
I did a bit of googling about an issue which i'm facing at my end about the Redirect URL returning 500 rather than the expected 302. I found the npm request() can be used for redirects. However I'm not able to get the response headers as it always returns 500. But when I used the API end points manually with Postman (with interceptors turned ON) along with body and headers, I was able to get 302 redirects. This is essentially used for Automation testing for API
request(
url: 'https://blah/blah',
client_id:'something.com.au'
redirect_uri:'http://something' // used for mobile app and so it is OK to be have a valid url
response_type :'code'
scope : 'ALLAPI',
Username : 'cxxx'
Password : 'ccxcxc'
headers : {
'Content-Type': 'application/x-www-form-urlencoded',
'followRedirect' : true
}, function (error, response) {
console.log('The response val is', response.statusCode);
});
Question:
Not sure if npm request can do the justice or Am I using request in-correctly or should I have to use axios/follow-redirects etc.. something like that. Please advise. If anyone can provide proper directions on this, it'll be really helpful
Thanks,
Brad
I met the same problem, needle works for me.
var needle = require('needle'),
url = 'https://www.ibm.com/common/ssi/cgi-bin/ssialias?htmlfid=GBE03831USEN&';;
needle.get(url, {follow_max: 5}, function(error, res) {
console.log(res.statusCode);
});
#all. I've resolved using form property but with using req.post() method which returned the statuscode as 302 with response headers. Thanks all once again.

Resources