How do you 'intercept' all HTTP requests in an EmberJs app? - javascript

I would like to be able to capture all HTTP requests and responses, and modify them, before they get to the rest of an EmberJs app. I would like to do this globally - across the entire app. I have not been able to find this digging through the API. How can this be done?
(Modification is to perform some conditional logic based in certain headers, or to add or modify certain headers).
In AngularJS, you can accomplish this using something like this:
App.factory('AppHttpInterceptor', function($q) {
return {
request: function(req) {
//modify request
return req;
},
response: function(res) {
// modify response
return res || $q.when(res);
}
};
});
App.config(function ($httpProvider) {
$httpProvider.interceptors.push('AppHttpInterceptor');
});

First, it's important to note that Angular and Ember are not built to serve the same purpose. They are both javascript frameworks, and that's about where the similarities end. Another big factor in the difference of async requests in the two framework is Angular's integration of promises into it's async services. Ember async services are not promise based, and therefore response interceptors are not possible (see my note below).
AngularJS provides $httpProvider as a configurable singleton that returns a configured instance of $http as a promise object. Angular focuses on services rather than methods (although it does have a few methods it gives you), and that's what sets Angular apart from other frameworks like Ember, which give you a structure to build services, but doesn't provide services in it's core.
Instead, with Ember, you'd have to build a service and service provider concept yourself. You could take something like cerebris/ember-rest, and extend it in such a way as to use properties you describe. This library provides an Ember.resource method, which you could use prototype to extend from there:
Ember.ResourceAdapter.extend({
_prepareResourceRequest: function(params) {
params.beforeSend = function (xhr, settings) {
//set your xhr interceptors here
}
}
});
Edit: Clarification on use of $ajax in ember and $http in Angular (promises vs callbacks)
The biggest difference on how angular makes response interceptors possible, is that async requests in angular are promises, whereas $ajax calls are not. Without getting too much into the weeds, you can assign variables to each step of a promise, making it available for mutation/handling along every step of the way, whereas with $ajax, you can only perform operations when the data has completely returned. With Promises, assign variables to represent states at any point during the lifecycle of the promise, and using that reference, you can mutate the promise as needed, at any point in time prior to the event of the promise fully resolving.
Thus why it's possible to do request interceptors with $ajaxPrefilter but there is no good way to do response interceptors, using the abstract configuration approach with $ajax. To truly do in Ember what AngularJS does with $http, you need to create a promise based async request/response service, as opposed to utilizing non-promise based xhr requests such as $ajax.
jQuery does provide an $ajaxSetup() method, which you might be able to set a dataFilter property to and define a handler function, however this is not recommended. With angular, the $httpProvider can be configured by module, and through de-coupling and Separation of Concerns, this can become truly powerful, allowing you to encapsulate and cascade http interceptor configurations with a lot of control. Making the same changes to your ajax settings will register themselves on the global jquery namespace, and can cause conflicts if you need to grow your app.
One video I found particularly englightening on this subject was from ng-conf 2014: Christion Lilley: Going Postal with Angular Promises
Edit 2: addressing Ember.RSVP
While Ember.RSVP is indeed a promise class useable in the framework, it does not have any methods available to perform resource requests. This means you have to manually assign an http request instance to an instance of RSVP.deferred such that it resolves your http request before returning the promise.
This allows you to do interceptors on both sides of each individual request, but does not provide a solution for configuring interceptors for all requests. You'd have to create another function or service for that, and extend RSVP with this function.

Related

Angular: Http vs fetch api

Although I understand the way Angular makes HTTP requests, I prefer using the built-in Fetch API because I don't have to subscribe and unsubscribe just to make 1 simple request. I tried using it in my angular app and it didn't throw any errors, page didn't reload (still a SPA), everything worked fine. I suppose there is a time and place for everything.
This:
fetch('/api/get_post_by_id/1').then(r => r.json()).then(j => { console.log(j); });
Is more simple, than this:
const obs = this.http.get('/api');
obs.subscribe(() => { ... });
obs.unsubscribe();
Basically my question is, is it wrong to use the Fetch API when developing Angular apps?
Like any tool you encounter during development each tool will have advantages and disadvantages and it's good to think about why a tool is being used.
When we take a look at HttpClient it originally simplified the mess that was XMLHttpRequest. In the same way $.ajax originally did it, HttpClient was the 'angular solution'. It followed the ideology of everything being an observable which has advantages (you can mix and match it with other observables) and disadvantages (it adds a lot of bloat).
Advantages of HttpClient
It allows easy mixing and matching of two observables (e.g. let's say you have one observable which returns multiple times and an API request which returns once and you want to zip the two together it's trivially easy to do). Of course, turning a promise into an observable only requires importing from from rxjs
If you forget adding an abstraction - having all requests going through an apiService layer - you can still use an interceptor to achieve similar results magically.
It will increase the learning curve for new Angular developers, thus making your job more special.
HttpClient does some magic for you such as automatic retrying of requests.
It's already included in Angular, so if you need to support 7 year old browsers like IE11 you don't need to load a polyfill like with fetch.
Advantages of fetch
Important : All fetch related code assumes you do create a very simple abstraction (e.g. apiService in these examples). This is the same as setting up an interceptor in HttpClient-land.
It's the new industry standard. Once you know it, it can be used anywhere (most likely once Angular and React die - which at some point they will - fetch will still most likely be around).
It simplifies working with service workers as the Request and Response objects are the same you are using in your normal code.
HTTP requests will typically return once and only once (of course you might be loading a file chunk by chunk, but that's a very rare exception to the rule). fetch is built around the norm (single return values), not the exception (multiple return values), and thus returns a Promise rather than a stream-like-type. The advantage this results in is that it plays nicely with any and all relevant new language features such as async and await. Compare:
try {
const posts = await this.apiService.get('/posts');
// work with posts
} catch (error) {
// handle error
}
console.log('this happens **after** the request completes');
with
this.http.get('/posts')
.subscribe(posts => {
// work with posts
})
.catch(error => {
// work with error
});
console.log('this happens **before** the request completes');
(of course you can also toPromise each Observable that will complete (or add .pipe(take(1)), but that's frankly a bunch of superfluous code (which I still often end up using))
It simplifies onboarding of new people. When you see a request such as
this.apiService.get('/posts');
a developer from any framework can come and right-click on .get and check out the function definition where things such as a domain and an authentication header being added will be clearly defined.
On the other hand when a developer sees
this.http.get('/posts')
they have no way of easily discovering if and where the request might be changed unless they are aware of Angular specific magic. This is one of the reasons why Angular is considered to have a steep learning curve.
There is no risk of there being magic you aren't aware of such as automatic retrying of requests which can end up in the same request triggering 4 times on the server and you having no idea how that's possible.
It's already included in the browser - provided you don't need to support 7 year old browsers - so it can result in a slightly smaller bundle size.
Complete tie
I sincerely don't see how types are a difference, as typing a return value from any method can be done. <Model>this.apiService.get('/posts') works perfectly fine.
Conclusion
Personally, I would strongly recommend anybody to use fetch with an abstraction layer. It results in easier to read code (even a junior who hasn't ever seen async and await is able to read it) and even if you are in a rare situation where your apiService has to return multiple times you are still completely free to do so as you're fully in control. And in general, you should only not use the standard (fetch) if the alternative offers significant advantages. Even if it was a perfect tie in terms of advantages and disadvantages it probably isn't worth going for a 'framework specific' solution.
HttpClient just doesn't seem to offer any tangible advantages beyond saving a couple of minutes of time during the initial project setup where you don't need to set up an abstraction layer for API requests.
this.http.get('/api').subscribe(j => console.log(j));
You made it too complicated, above is all you need and it is similar to the code you have for window.fetch. You can use the generic version and it will be typed to the expected interface as well making it even easier.
this.http.get<IModel>('/api').subscribe(j => console.log(j));
There is no need for unsubscribe and you only need to pipe + map if you want to transform the result before hand. Calling json() was required for the "old" HttpModule which has been replaced with (technically extended by) HttpClient as of version 4.3
And if you still prefer Promise over an Observable you can always call toPromise().
this.http.get('/api').toPromise().then(j => console.log(j));
See also HttpClient
is it wrong to use the Fetch API when developing Angular apps?
It is not wrong but there are reasons not to do it. You can inject HttpClient and write comprehensive unit tests for various scenarios, URLs, Http verbs, etc. Doing the same if you have used window.fetch throughout your code becomes much more difficult. HttpClient is also richer in that you can use the type system for your results. Observables are also more feature rich than Promises and this can come in handy in more complex scenarios like sequencing calls when dealing with multiple micro services or canceling a call if additional user input is received.
So there are multiple reasons to use the HttpClient and I can't think of a single one not to besides that it is a small learning curve.
So, after 2 years of using Angular, here are some things i found out:
There is this library called RxJS - https://rxjs-dev.firebaseapp.com/guide/overview, which is written in TypeScript (superset of JavaScript). It is like one of thee best libraries for JavaScript.
Basically, it makes event-driven apps a breeze in JS by using the Observable paradigm. A Promise can only return a value once and is async only. Observables can be used to return a single value OR multiple values and can be sync or async (depending on how you use it), you can add pipes and operators to transform the results before it is used/consumed by the subscriber to it and etc; it gives a functional programming feel to using it, which is great. It is far more feature-rich than promises.
A subscriber listens or "subscribes" to and Observable (the .subscribe() call on an observable). An Observable emits 3 types of events: next, error, and complete. Next means an event with/without data was emitted, error means there was an error within the event stream, and complete means the event stream has ended and the observable will not emit anymore.
Now, just because there was an error emitted, does not mean the event stream stopped. An event stream is only stopped when the complete event happens. Also, a subscriber can unsuscribe from an observable, meaning it will stop listening to the event stream.
The HttpClient service from Angular is built using RxJS. They basically wrapped it over the old XmlHttpRequest way of making requests - https://github.com/angular/angular/blob/main/packages/common/http/src/xhr.ts#L193.
When you make a request using Angular's HttpClient service, it automatically completes the observable on ok response, so there is no needed to call unsuscribe on the observable since it's done anyway; it won't call complete on error response but http calls only response once.
Observables don't execute until they are subscribed to; a Promise executes immediately.
I would say Observables are far better to use over Promises; i don't see RxJS leaving any time soon or ever.
I wanted to leave this a comment but I'm too new here. For the abstraction you could use HttpBackend for the fetch call and just extend the HttpClient.
import { HttpBackend, HttpClient, HttpEvent, HttpHeaders, HttpRequest, HttpResponse } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable, Observer } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class FetchBackend implements HttpBackend {
handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
if (!('fetch' in window)) {
throw new Error(
`Fetch not supported with this browser`);
}
if (req.method === 'JSONP') {
throw new Error(
`Attempted to construct Jsonp request without HttpClientJsonpModule installed.`);
}
return new Observable((observer: Observer<HttpEvent<any>>) => {
const request = new Request(req.urlWithParams, { method: req.method});
fetch(request)
.then((r) => {
r.json().then((body) => {
const headers = new HttpHeaders();
r?.headers.forEach((value, name) => {
headers.append(name, value)
})
observer.next(new HttpResponse({
url: r.url,
status: r.status,
statusText: r.statusText,
body: body,
headers: headers
}))
});
})
});
}
}
#Injectable({
providedIn: 'root'
})
export class FetchClient extends HttpClient {
constructor(handler: FetchBackend) {
super(handler);
}
}
StackBlitz

Angular Data that does not affect the view: use directive, object, or function?

I have a repeated set of API calls in an Angular controller.
The relevant data is of course the API URI, POST or GET, some header data, and JSON objects. The API call always returns a JSON object.
I started to use a Directive but that seems most relevant for data that is used with $scope (e. g. in the View). This data runs under the radar and might eventually generate data used in the view but most usually not and most usually not in a way that can be abstracted.
So: Does this mean I shouldn't use a directive? If I don't use a directive, would it be better to use a JS Object (seems more modular) or Function (seems more variable friendly) to handle this code?
Yes, I get that objects can contain functions, but functions can also contain callbacks so...looking for kind of a "best practices" here. In terms of modularity and flexibility.
You should create Angular service for that.
https://docs.angularjs.org/guide/services
Your service will contain a method, lets say "getResults" which will make an API call and return either data or a promise ($http). Then you can inject you service to your controller and use that method to get the data and assign it to $scope.
An Angular service is certainly preferred to a more general JavaScript one because it allows you to take greater advantage of Angular's scope and other such things. Between Angular's Factory, Service, and Providers, a Service is the most in line with what you're trying to do since a Factory is too basic and generally used to solve smaller problems while a Provider is used -- as it says in the Angular docs -- "only when you want to expose an API for application-wide configuration that must be made before the application starts." Which is not what you're trying to do.

Controllers <-> Services interaction and unit-testing : Am I doing this wrong?

I'm building an AngularJS app, and I would it to be respectful or the best practices.
Thus, when I have to call an external $resource or $http request, I do it in an external Service/Factory.
My problem is I don't know what is the best way for retrieving returned value of the Service into the calling Controller.
Currently, what I do is the following :
The controller calls the Service
The Service does the $http call and check the promise.
If promise is successful, the Service $broadcast an event with the returned object.
The Controller catches that event and does operations.
It works great and allows me to use the same event after different requests (ex: In a discussion, after retrieving all messages and after posted myself a message, the same event "new messages to display" is called)
.
But I finally decided to set up testing processes in my application (better late than never), and I realize that I could do it wrong.
--> When unit-testing my Controllers I want to mock some of my Services for returning given values. But as my Controller calls Services which doesn't returns anything (they fire events instead) I think it will be pretty hard and not natural to check Services "return" values. (I can always check if the Service has been called, but not the result).
.
Your opinion, have I done misconception errors ? I consider getting the promises directly into Controllers when calling Services, is this a good (better?) way to do it ?
I aware that each application have its own logic, but I think in AngularJS the number of "working" logics (that preserves modularity, and testability) are particularly restricted to some set of choices and best practices.
Any suggestion would be appreciated.
Without seeing your code, I have my ideas:
Your controller could receive that promise and do what it needs to do. There is no real need to broadcast anything. Your service call $http and then return the promise. When $http promise is resolved, your controller will know and can do what you need to do.
Testing functions in a service that doesn't return anything is not a problem, that is what spyOn is. You can check that the function has been called and that should be enough for your controller. You don't actually care what happens in the service, you cares about your controller (in the test controller, of course).
Please don't use events for such kind of interaction. They make a mess inside of the code and reduce maintainability. Sometimes you can use them but it is fine only for certain operations and for some specific situations. Using promises is good approach.
Here you have three different options:
Just return the $http promise object and handle it inside of your controller
Make your own promise with $q service and place inside of it your own logic for handling the response from $http or direct returning result (it is more flexible approach than the first one)
Just pass to the services a function callback which you can call there inside of your service to pass the result back to controller.
But you definitely don't need to use events in these cases.
What is related to unit-testing you will configure $httpBackend service to mock your queries and in this case everything will work fine and you can test anything you need ($httpBackend). It means that you can inject your service and it works fine (as instead of real http call it will return the object configured as a response in the $httpBackend). So you can still test your controller without need to make anything complicated to your services.

node.js and a singleton that has an asynchronous call in getInstance

I have a implemented a singleton following the model described in the book by Addy Osmani book, Learning Javascript design patterns.
This singleton is setting up a soap connection. This is an asynchronous call and I want to perform that in the getInstance call so the follow on calls can be guaranteed to have the connection that is completely up...
One thought i have is to pass in a callback to getInstance, make that call in my main.js function and by the time other scripts get to needing a connection, it will be up. And every other consumer of the soap connection, pass it null for the callback.
Is this a hack or a good way to do this?
If it is a not standard way of doing this, what do you suggest?
When dealing with events, such as XMLHTTPRequest (be it SOAP or JSON) it's common to use a callback function.
However it's preferred to use Promises. Promises are designed to be adept at dealing with asynchronousness. The most notable advantage over callbacks is that Promises come with error handling, progression and cancellation built in.
Most popular frameworks and libraries include an implementation of Promises.
A minor note: a Singleton as a design pattern is, more often that not, an anti-pattern. Be very weary when using it, especially in the face of testability. I'm not familiar with Addy Osmani's work so I can't comment on this specific case.
The notion of a Singleton becomes moot when you apply good Dependency Injection.
There are few ways of doing this:
Make you singleton an EventEmitter. Emit event ready or initilized when initialization completes. Problem: if a client starts listening after singleton is initialized, it will never catch initialized event. You can add initialized property and set it to true when initialization completes, to allow clients check object status. Still using it will require static check of the .initialized property, then setting listener or proceeding right away.
Add callback to getInstance. If the object is initialized already, callback is called on next tick.
Queue all requests before initialization is completed. It's super-convinient, but also complex to implement.
By the way, don't use getInstance in node.js, it's more like java-style. Just module.exports = new MyClass will do. In this case 2 method is not applicable as is, but you can ad a special method for just setting such a callback, like onReady().

AngularJS $http and $resource

I have some web services that I want to call. $resource or $http, which one should I use?
$resource: https://docs.angularjs.org/api/ngResource/service/$resource
$http: https://docs.angularjs.org/api/ng/service/$http
After I read the two above API pages I am lost.
Could you please explain to me in plain English what is the difference and in what situation should I use them? How do I structure these calls and read the results into js objects correctly?
I feel that other answers, while correct, don't quite explain the root of the question: REST is a subset of HTTP. This means everything that can be done via REST can be done via HTTP but not everything that can be done via HTTP can be done via REST. That is why $resource uses $http internally.
So, when to use each other?
If all you need is REST, that is, you are trying to access a RESTful webservice, $resource is going to make it super easy to interact with that webservice.
If instead, you're trying to access ANYTHING that is not a RESTful webservice, you're going to have to go with $http. Keep in mind, you could also access a RESTful webservice via $http, it will just be much more cumbersome than with $resource. This is the way most people have been doing it outside AngularJS, by using jQuery.ajax (equivalent of Angular's $http).
$http is for general purpose AJAX. In most cases this is what you'll be using. With $http you're going to be making GET, POST, DELETE type calls manually and processing the objects they return on your own.
$resource wraps $http for use in RESTful web API scenarios.
Speaking VERY generally: A RESTful web service will be a service with one endpoint for a data type that does different things with that data type based on HTTP methods like GET, POST, PUT, DELETE, etc. So with a $resource, you can call a GET to get the resource as a JavaScript object, then alter it and send it back with a POST, or even delete it with DELETE.
... if that makes sense.
$http makes general purpose AJAX call, in which general means it can include RESTful api plus Non-RESTful api.
and $resource is specialized for that RESTful part.
Restful Api came to prevalent in recent years because the url is better organized instead of random url made up by programmers.
If I use a RESTful API to construct the url, it would be something like /api/cars/:carId.
$resource way to fetch data
angular.module('myApp', ['ngResource'])
// Service
.factory('FooService', ['$resource', function($resource) {
return $resource('/api/cars/:carId')
}]);
// Controller
.controller('MainController', ['FooService', function(FooService){
var self = this;
self.cars = FooService.query();
self.myCar = FooService.get('123');
}]);
This will give you an resource object, which is accompanied with get, save, query, remove, delete methods automatically.
$http way to fetch data
angular.module('myApp', [])
// Service
.factory('FooService', ['$http', function($http){
return {
query: function(){
return $http.get('/api/cars');
},
get: function(){
return $http.get('/api/cars/123');
}
// etc...
}
See how we need to define each common operation on RESTFul API. Also one difference is that $http returns promise while $resource returns an object. There are also third-party plugins to help Angular deal with RESTFul API like restangular
If the API is something like /api/getcarsinfo. All left for us is to use $http.
I think the answer depends more on who you are at the time you're writing the code. Use $http if you're new to Angular, until you know why you need $resource. Until you have concrete experience of how $http is holding you back, and you understand the implications of using $resource in your code, stick with $http.
This was my experience: I started my first Angular project, I needed to make HTTP requests to a RESTful interface, so I did the same research you're doing now. Based on the discussion I read in SO questions like this one, I chose to go with $resource. This was a mistake I wish I could undo. Here's why:
$http examples are plentiful, helpful, and generally just what you need. Clear $resource examples are scarce, and (in my experience) rarely everything you need. For the Angular newbie, you won't realize the implications of your choice until later, when you're stuck puzzling over the documentation and angry that you can't find helpful $resource examples to help you out.
$http is probably a 1-to-1 mental map to what you're looking for. You don't have to learn a new concept to understand what you get with $http. $resource brings along a lot of nuance that you don't have a mental map for yet.
Oops, did I say you don't have to learn a new concept? As an Angular newbie you do have to learn about promises. $http returns a promise and is .thenable, so it fits right in with the new things you're learning about Angular and promises. $resource, which doesn't return a promise directly, complicates your tentative grasp on Angular fundamentals.
$resource is powerful because it condenses the code for RESTful CRUD calls and the transformations for input and output. That's great if you're sick of repeatedly writing code to process the results of $http yourself. To anyone else, $resource adds a cryptic layer of syntax and parameter passing that is confusing.
I wish I knew me 3 months ago, and I'd be emphatically telling myself: "Stick with $http kid. It's just fine."
I Think it is important to emphasize that $resource expects object or array as response from server, not raw string. So if you have raw string (or anything except object and array) as a response, you have to use $http
When it comes to choose between $http or $resource technically speaking there is no right or wrong answer in essence both will do the same.
The purpose of $resource is to allow you to pass in a template string (a string that contains placeholders) along with the parameters values. $resource will replace the placeholders from the template string with the parameter values those being passed as an object. This is mostly useful when interacting with RESTFul datasource as they use similar principles to define the URLs.
What $http does is to perform the Asynchronous HTTP Requests.
resource service is just useful service for working with REST APSIs.
when you use it you don't write your CRUD methods (create,read,update and delete)
As far as I see it, resource service is just a shortcut,
you can do anything with http service.
One thing i noticed when using $resource over $http is
if you are using Web API in .net
$resource is tied up into one controller that execute a single purpose.
$resource('/user/:userId', {userId:'#id'});
[HttpGet]
public bool Get(int id)
{
return "value"
}
public void Post([FromBody]string value)
{
}
public void Put(int id, [FromBody]string value)
{
}
public void Delete(int id)
{
}
While $http could be of anything. just specify the url.
$http.get - "api/authenticate"
[HttpGet]
public bool Authenticate(string email, string password)
{
return _authenticationService.LogIn(email, password, false);
}
it's just my opinion.
The $resource service currently does not support promises and therefore has a distinctly different interface to the $http service.
What I could understand is that if you are having a RESTFUL resources to manage, using $resource will let you define the resource once in code, and use the resource for multiple operations on the resource. This increases the readability and maintainability of the code.
If you just want to have general purpose calls not managing it like post, delete, update, you may go with $http or $resource (as you prefer).

Categories