clear cache of angular $resource - angularjs

In my use case I have Carts and LineItems. My REST service has the following resource urls:
get|post|delete|put api/v1/carts/:cartId
get|post|delete|put api/v1/carts/:cartId/lineItems/:lineItemId
get|post|delete|put api/v1/lineItems/:lineItemId
the probelm is that when I do:
delete api/v1/carts/Default/lineItem/:lineItemId
and then I do:
get api/v1/carts/Default
angular does not hit the server to get the cart, but it gets it from cache which returns the deleted line item back in the cart
I tried all sorts of trick, tried disabling the cache by adding the {cache: false} option, but could not get it to work
the only way I was able to get it to work was if I make a POST request to
api/v1/carts/Default
with an empty body, which tells angular that the resource has changed and clears the cache.
Even though it works it seams like a hacky solution, so I was wandering if someone might have a suggestion of what I am doing wrong.

Get requests are cached by browsers. Simplest way is to use timestamp:
instead of GET /user/100 use GET /user/100?time=120229393
With such request you will always hit server.
If you need this in multiple requests, you can make http interceptor to add timestamp param to request.

Related

Should I use POST or GET if I want to send an Array of filters to fetch all articles related with those filters

I havent find ressources online to solve my problem.
I'm creating an app with React Native that fetches and shows news articles from my database.
At the top of the page, there's some buttons with filters inside, for example:
one button "energy",
one button "politics"
one button "people"
one button "china"
etc...
Everytime I press one of those buttons, the filter corresponding is stored in an array "selectedFilters", and I want to fetch my database to only show articles that are corresponding to those filters.
Multiple filters can be selected at the same time.
I know one way of doing it, with a POST request:
await fetch('187.345.32.33:3000/fetch-articles', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'},
body: 'filters=${JSON.stringify(selectedFilters)}'
});
But the fact is, I read everywhere, and I also was teached, that POST request are used when creating or removing, and theoretically, what I should use is a GET request.
But I don't know how to send an Array with GET request.
I read online that I can pass multiple parameters to my url(for example: arr[0]=selectedFilters[0]&arr[1]=... but the fact is I never know in advance how many items will be in my array.
And also I'm not sure if I could write exactly the same way as my POST request above, but with GET:
await fetch('187.345.32.33:3000/fetch-articles', {
method: 'GET',
headers: {'Content-Type':'application/x-www-form-urlencoded'},
body: 'filters=${JSON.stringify(selectedFilters)}'
});
or if I can only pass items in the url, but does this work ?
await fetch('187.345.32.33:3000/fetch-articles?arr[0]=${selectedFilters[0]', {
Or even better if something like this could work:
await fetch('187.345.32.33:3000/fetch-articles?filters=${JSON.stringify(selectedFilters)}', {
Thanks for your help
You should definitely use a GET request if your purpose is to fetch the data.
One way of passing the array through the URL is by using a map function to create a comma separated string with all the filters. This way you would not need to know in advance how many elements are in the array. The server can then fetch the string from the URL and split it on the commas.
One more method you can try is to save a filters array on the server side for the session. You can then use a POST/PUT request to modify that array with new filter as user adds or remove them. Finally you can use an empty GET request to fetch the news as the server will already have the filters for that session.
But the fact is, I read everywhere, and I also was teached, that POST request are used when creating or removing, and theoretically, what I should use is a GET request.
Yes, you do read that everywhere. It's wrong (or at best incomplete).
POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” (Fielding, 2009)
It may help to remember that on the HTML web, POST was the only supported method for requesting changes to resources, and the web was catastrophically successful.
For requests that are effectively read only, we should prefer to use GET, because general purpose HTTP components can leverage the fact that GET is safe (for example, we can automatically retry a safe request if the response is lost on an unreliable network).
I'm not sure if I could write exactly the same way as my POST request above, but with GET
Not quite exactly the same way
A client SHOULD NOT generate content in a GET request unless it is made directly to an origin server that has previously indicated, in or out of band, that such a request has a purpose and will be adequately supported. An origin server SHOULD NOT rely on private agreements to receive content, since participants in HTTP communication are often unaware of intermediaries along the request chain. -- RFC 9110
The right idea is to think about this in the framing of HTML forms; in HTML, the same collection of input controls can be used with both GET and POST. The difference is what the browser does with the information.
Very roughly, a GET form is used when you want to put the key value pairs described by the submitted form into the query part of the request target. So something roughly like
await fetch('187.345.32.33:3000/fetch-articles?filters=${JSON.stringify(selectedFilters)}', {
method: 'GET'
});
Although we would normally want to be using a URI Template to generate the request URI, rather than worrying about escaping everything correctly "by hand".
However, there's no rule that says general purpose HTTP components need to support infinitely long URI (for instance, Internet Explorer used to have a limit just over 2000 characters).
To work around these limits, you might choose to support POST - it's a tradeoff, you lose the benefits of safe semantics and general purpose cache invalidation, you gain that it works in extreme cases.

Using Angular Mock Backend resource multiple times

I am trying to do backend less development in Angular while working disconnected from the backend resources.
Most functionality works fine, but if I try to use any resource a second time I get an error:
Error: Unexpected request: GET /localPTicket?ticket=123
No more request expected
The scenario I am mocking is one where, for every request to a backend service, I have to first make a Get call to get a valid Proxy Ticket, the response from this is then passed to the next API call.
I have set up a plunker that demonstrates the issue:
https://plnkr.co/edit/KKa6MXcnbK1gcMiBB7MI?p=preview
I think that the issue is related to flushing the mock requests, but my understanding of the documentation is that using ngMockE2E this should not be an issue.
Thanks for any pointers!
Les
It's because your are using global regexes.
Global regexes in JavaScript can be very confusing since they have a state. The first time you call it it returns the first match in the string, the second time you call it it returns the next match in the string. If there are no more matches it will return that there were no matches and reset its state.
Simply remove the g from the end of your regexes and it should behave as you expect.

Query AngularJS's $cacheFactory values

I've correctly set Restangular to cache my http requests via:
Restangular.withConfig(function(RestangularConfigurer) {
RestangularConfigurer.setDefaultHttpFields({cache: true});
});
I would like, however, to be able to manually certain cached elements at a given point in time, eg when they become obsolete due to the user modifying these objects. Is there a way to do this? I've tried:
$cacheFactory.get('$http').info()
Object {id: "$http", size: 7}
Just make use of the $cacheFactory API as documented here:
https://docs.angularjs.org/api/ng/service/$cacheFactory
For instance, to invalidate a given cache entry:
$cacheFactory.get('$http').remove(myGetUrlToInvalidate);
myGetUrlToInvalidate is a string representation of your GET request URL. You may have to test to find out whether its the
relative or absolute URL, check out following stackoverflow discussion for more details:
How to refresh / invalidate $resource cache in AngularJS
Also of interest this stackoverflow discussion pointing to an alternate cache implementation:
Is there a way to get all of the keys out of a cache in Angular, specifically the template cache?
Restangular resources:
https://github.com/mgonto/restangular#can-i-cache-requests
https://github.com/mgonto/restangular#setdefaulthttpfields

CakePHP: Caching does not work

I am having the following issues: my cakephp app is not handling the cache thing properly. As suggested by every result in google, I created a function in the model to manually delete the cache:
public function afterSave($created) {
Cache::clear();
clearCache();
}
Unfortunately, this is doing nothing. Doesn't delete anything, and I still have the problem.
In case I have no explained myself properly, I will give an example of what happens:
I go with my browser to a page that shows a list of the last 5 records in my database. Then I go and add another record. I come back to the page that shows the last 5, and the information is not updated. It uses the cache and comes back with outdated info. If I press F5, then he page trully reloads and I see the trully 5 last records.
And that's it, I don't know what to do. The whole app works like crap, because you do something and it never appears unless you refresh the page with F5, which is something of course users are unaware, leading them to think "nothing was added" when it actually was.
Cache::clear() will only clear entries that have expired.
Try Cache::clear(FALSE). Works if you have CakePHP 2.x.
I did this to solve the problem: In the controllers, inside beforefilter function I made a check, if the action is something I disable the cache.
The actions you choose won't have browser cache.
function beforeFilter(){
if ($this->action == 'youraction'){
$this->disableCache();
}
}
Use of caching required lots of thinking, where to use where to not. If your update is frequent, don't use caching there.
We use caching where data rarely change, at that moment it is win-win situation.
Cache::clear($check, $config = 'default')
Destroy all cached values for a cache configuration.
cakephp Caching

CRUD with just GETs and POSTs

Instead of the default sync method, with DELETEs, PUTs &c, I'll have to use GETs and POSTs to do the CRUD operations. Is there a more elegant approach to this problem than overriding save(), fetch() and other methods?
Backbone has built in support for such things through emulateHTTP:
emulateHTTP Backbone.emulateHTTP = true
If you want to work with a legacy web server that doesn't support Backbones's default REST/HTTP approach, you may choose to turn on Backbone.emulateHTTP. Setting this option will fake PUT and DELETE requests with a HTTP POST, setting the X-HTTP-Method-Override header with the true method. If emulateJSON is also on, the true method will be passed as an additional _method parameter.
Backbone.emulateHTTP = true;
model.save(); // POST to "/collection/id", with "_method=PUT" + header.
So set Backbone.emulateHTTP to true and adjust your server-side code to look at the X-HTTP-Method-Override header to see what POST requests are supposed to mean.

Resources