In okhttp I'd like to handle Last-Modified and ETags but without caching the whole response - retrofit

I'm using okhttp and Retrofit to call a REST service. The data that is returned from that service is store in my Android app inside an sqlite database.
Whenever I call the REST api, if the data hasn't changed (determined by either ETag or Last-Modified header) I want to have the Retrofit callback do nothing (data in DB is ok). Otherwise I want to download the updated JSON from the REST service and update the database (via the onSuccess method of my callback).
The okhttp examples on caching all setup disk caches for the responses, I just need to cache/store the Etag/last-modified time of each request (and not the whole response).
Should I be doing this through a custom Cache implementation that I pass to okhttp, or is there a better interface I should be using with okhttp or Retrofit?
Once I have the implementation setup do I just need to handle the 304 "errors" in my onFailure callback and do nothing?

To know if you've got a 304 as response, in the onResponse callback you can catch it as follows:
if (response.raw().networkResponse().code() == 304){
// Do what you want to do
}
At least, this is when you are using Retrofit 2 and okHttp 3. Not sure about earlier versions, but I guess it would be kind of the same? You could always try to find a 304 response when setting breakpoints in the response.

Related

Meaning of ETag in firebase response

Could you please explain what does it mean ETag header in firebase response on firebase function's call?
Rephrasing question.
In my case I don't need ETag, and I want to change the behaviour.
How can I implement this?
For example, I have simple function on the cloud side that return json:
const getObject = functions.https.onCall((data, context)=>({x:1, y:2}));
In browser I see ETag presented in http response, as you can see I don't get any data from cloud store in my handler.
Next question, call (for example, in angularfire) to callable functions translates to http POST request, what is the best way to modify response in onCall handler to force caching abitrary json data on the client and reverse proxy side?
The ETag header has the following purpose:
The ETag HTTP response header is an identifier for a specific version of a resource. It allows caches to be more efficient, and saves bandwidth, as a web server does not need to send a full response if the content has not changed. On the other side, if the content has changed, etags are useful to help prevent simultaneous updates of a resource from overwriting each other ("mid-air collisions").
You use the ETag for conditional updates. Typically when you don't want to overwrite another user's changes to a document.
Another use case is when you're making a partial update to a document and the change assumes that the rest of the document has not changed in the meantime; there are invariants to protect.
Don't confuse this with the concurrency model for transactions. Server-side SDKs just keep retrying on failures caused by write contention. This just brute forces your changes in.
This is more for when a user has been editing a customer's order for 10 minutes, then saves it, but some other user, like a customer services person, has already made changes, so you can't overwrite them else their changes will be lost.
So you need to inform the user that someone else has changed stuff and they need to reload and potentially lose their edits.

JMeter http request DELETE with body

I have proprietary http based API to test from JMeter. Unfortunately some of the endpoints of the API are expecting http DELETE method with a request body (I know its questionable API design to use DELETE with request body, but I have no ability to change that API and need to test it).
How can I test it from JMeter? It seems that standard HttpRequest sampler silently ignores my body payload without any warnings. (When I try it in POSTMAN its sending a request body for DELETE method)
I did find an old JMeter plugin called HTTP Raw Request that somewhat helps but still doesn't auto-calculate "Content-Length:" http header for my body payload...so I have to do it manually for every test case - which is a pain for dynamically generated data payloads.
So my question still remains: How can I test HTTP DELETE with request body from JMeter?
Here is the screenshot:
NOTE1: Starting from jMeter ver. 3.1 (see bugzilla #60358) it was fixed for Http GET request to be able to send body in the request...but DELETE was not added.
NOTE2: See bugzilla #61443 for the DELETE request with body.
NOTE3: I'm using client implementation called "Java".
As per reference docs:
http://jmeter.apache.org/usermanual/component_reference.html#HTTP_Request
There are 2 implementations for http request sampler. The non default one called "Java" has this issue with not passing DELETE request body.
Luckily the default implementation called "HttpClient4" that correctly passes request payload for DELETE operation as per JMeter data entry screen.
To change implementations for http request sampler you have to go to "advanced" tab of the HTTP Request Sampler and select client implementation "HttpClient4" instead of "Java". Here is the screenshot:
After that when executed it correctly sends request payload for DELETE operation. Here is the screenshot:

Caching a JSON response using ETag in a React Native app

What is the best way to implement the following scenario in a React Native app?
Make an HTTP request to the server, get a JSON response and an ETag header.
Save this JSON response in a way that will persist even after the app is restarted by the user.
Whenever this HTTP request is repeated, send an If-None-Match header.
When you get a "Not Modified" response, use the version in the persisted cache.
When you get a "Successful" response (meaning the response has changed), invalidate the persisted cache, save the new response.
Does React Native have a component that does these things out of the box? If not, what is the most common way people use to handle this?
The fetch() API of React native is following the http caching spec and it provides this feature. When you hit a 304 a 200 old response will be found in the cache and be reused.
Details:
https://github.com/heroku/react-refetch/issues/142
As answered at: https://stackoverflow.com/a/51905151
React Native’s fetch API bridges to NSURLSession on iOS and okhttp3 on Android. Both of these libraries strictly follow the HTTP caching spec. The caching behavior will depend primarily on the Cache-Control and Expires headers in the HTTP response. Each of these libraries have their own configuration you can adjust, for example to control the cache size or to disable caching.
And this: How to use NSURLSession to determine if resource has changed?
The caching provided by NSURLSession via NSURLCache is transparent, meaning when you request a previously cached resource NSURLSession will call the completion handlers/delegates as if a 200 response occurred.
If the cached response has expired then NSURLSession will send a new request to the origin server, but will include the If-Modified-Since and If-None-Match headers using the Last-Modified and Etag entity headers in the cached (though expired) result; this behavior is built in, you don't have to do anything besides enable caching. If the origin server returns a 304 (Not Modified), then NSURLSession will transform this to a 200 response the application (making it look like you fetched a new copy of the resource, even though it was still served from the cache).
Oof. Been over a year. I assume you know this is a resounding "no," right? You'll have to parse the response headers to grab the ETag and store that on the device (you're not using the browser) and then add the header to the subsequent requests after retrieving it from your storage mechanism of choice.
I just found this because I was looking to see if anybody had done this in React, let alone React Native, and I'm not seeing anything.
Whelp, time to roll up my sleeves and invent this thing...
okay, this is my current solution, not production tested yet. would love your feed back googlers.
i use Axios, but if you dont you still implement this around what ever wrapper you have around fetch -unless u use native fetch !-
import api from 'your api wrapper.js'
api.etags = new Set;
api.cache = new Set;
api.addRequestTransform(request => {
const etag = api.etags.get(request.url);
if (etag) {
request.headers['HTTP_IF_NONE_MATCH'] = etag;
}
})
// or whatever you use to wrap ur HTT
api.addResponseTransform(response =>{
if (
response.status === 304 &&
response.headers &&
response.headers.etag &&
api.cache.has(response.headers.etag)
) {
console.log('%cOVERRIDING 304', 'color:red;font-size:22px;');
response.status = 200;
response.data = api.cache.get(response.headers.etag);
} else if (response.ok && response.headers && response.headers.etag) {
api.cache.set(response.headers.etag, response.data);
api.etags.set(response.config.url, response.headers.etag);
}
});
what we are doing here is saving response result into api.cache, and saving the etags into api.etag, then we send etag with request every time.
we can upgrade this to also remember the correct status code, or save etags to disk, duno. what do you think :) ?

Meteor http get retrieving only a subset of headers

In my Meteor (1.2) application, I make a client-side HTTP.get call over https to a remote server supporting CORS.
var getUrl= "https://remoteserver/;
HTTP.call('GET', getUrl , {}, function (error, response) {
console.log (response);
}
Now, the issue is that set-cookie string is present in HTTP headers of the response of such HTTP call in Chrome's DevTools' Network tab.
However when I call console.log (response) , they're not included. Actually only these 3 properties are printed in response['headers']:
Content-Type
cache-control
last-modified
Digging more in, I found out on Meteor Docs that
Cookies are deliberately excluded from the headers as they are a security risk for this transport. For details and alternatives, see the SockJS documentation.
Now, on the linked SockJS docs, it says that
Basically - cookies are not suited for SockJS model. If you want to authorise a session - provide a unique token on a page, send it as a first thing over SockJS connection and validate it on the server side. In essence, this is how cookies work.
I found this this answer about sockJS but it looks outdated an not specific to Meteor.
The remote server expects me to use cookie-set header, so I have no choice. Also, for established scalability reasons, the HTTP.call must be done client-side (server-side was not an issue at all)
What solution / workaround can I adopt?
This package looks to be designed to help in situations like this, though I have not used it:
https://atmospherejs.com/dandv/http-more

How server knows whether the request is Synchronous or Asynchronous?

When i make an ajax call to server the full page is not postback, only few amount of data goes to the server and return a response page.
But i am wondering about processing. How the Server or server code knows whether the request in normal call or Ajax call.
I request to experts, please clear my doubt.
Thanks in advance.
How the Server or server code knows whether the request in Normal call or Ajax call.
The server knows this if your javascript code marks the HTTP packet as such. E.g. in jQuery the HTTP header sent to the server has an X-Requested-With set and ASP.NET uses this to distinguish if HTTP packets are ajax calls or not.
To know more about HTTP packets you can inspect the ones sent either in a packet sniffer such as Fiddler or in a browser with dev. tools that monitors traffic. In the latter case you can see this in e.g. Chrome dev tools by doing the following:
Open up Chrome Developer Tools, Ctrl+Alt+I (or Cmd+Alt+I in Mac).
Select the Network tab (you may have to refresh the page to enable network monitoring)
Perform the Ajax call, the HTTP request made should show up in the list at the bottom.
Select the relevant packet, you should now see "Headers", "Preview", "Response", "Cookies" and "Timing" tabs for the selected packet.
Select the "Headers" tab
You may have to expand the Request Headers part. Among the headers should be X-Requested-With: XMLHttpRequest
Here is a screenshot of the tool looking at packages as I was editing this answer:
Note that ajax calls don't necessarily have to be asynchronous as they can be synchronous (blocking the javascript until response is loaded) as well. Synchronous calls are necessary sometimes, e.g. popup blockers don't allow you to open a browser window inside an asynchronous ajax callback.
How the Server or server code knows whether the request in Normal call or Ajax call
It doesn't. There is nothing about an HTTP request sent by Ajax that is any different from any other HTTP request.
The code that makes the request can do something to make it recognisable (e.g. by adding a query string, by changing the Accept header to something more suitable for the context (such as Accept: application/json) or by adding additional HTTP headers (some libraries add X-Requested-With: XMLHttpRequest).
None of those are guarantees as someone could always make an HTTP request manually. They are fine for determining which view to return within your own application, but not if you are trying to implement any kind of security.
AJAX calls performs with instance of XmlHttpRequest prototype. 3rd argument of its .open() method is async:bool. So
xhr.open("GET", "http://example.com", true)
is async and
xhr.open("GET", "http://example.com") is sync.
jQuery get(), post() and ajax() is async by default and you need to pass async param to make it synchronous. So answer to your question: YOU tell the browser what request you want.

Resources