Sometimes you might need to modify HTTP requests and responses. This could be for a variety of reasons such as adding global logic handling for HTTP errors. With interceptors, you can easily accomplish this in your Angular applications.
The ability to intercept http calls in angular apps can be useful for a number of different reasons. To show how you do that, we're just going to set up a simple app here and we're going to define a config function and run function.
There's actually no UI to this example, but when the app initially runs, you can see we are injecting http resource and then just calling it "git" and we're going to fetch my GitHub repos. This is a good public API that you can use without, really, any restrictions.
In the config function, which is going to run before our run function, we're, instead, going to inject the http provider, because that's where we register our inceptors.
If we add a line here where we say httpprovider.inceptors.push, we can add our custom interceptor to the list here. You can see it's referencing this function up here. I split this out, just because it's a little easier to read in its own context up here, rather than within the definition down here.
This function is actually going to return an object and the keys on that object are going to determine, sort of, what part of the lifecycle they're involved in. We have a request key here, this function is going to be called when an http request is sent out and we'll get the config object there.
This is going to be called "window response returns" and this is going to be called if the response errors out. There's also a request error key that you can use, but it's not very common to need that, we're not going to look at that. If we just go ahead and save this and then run this app, you can see line four here, this is our request config object that our request function got. You can see that we have access to our URL here.
Since this is a git request, there's not a ton to look at, there are headers and a couple of other transform objects in here. But if this were a post request, you would also have access to that post data that you could then modify if you needed to.
Then finally, we see here, this code is just going to loop over the data that's returned, grab the first 10 out of the array, and then, write out the repo name. This is the list of the first 10 repos of mine from GitHub that came back.
To give a little bit of an example of the kinds of things you can do, in the request config interceptor, it's sometimes useful to actually modify the contents of your request.
Maybe you're server side method has a weird signature that you don't want to make the rest of your app deal with and you can clean things up in an interceptor. It can be useful for that sort of thing.
For this simple example, we're just going to, actually, modify the URL that we're using. I'm going to replace the URL with a version that replaces my username with Joel's username.
Config.url equals config.url.replace, and then, returns on its way. If we save that and then rerun this, we can now see...we're still seeing the same old config here. It does show it when you expand it. I was going to say it shows the old config, because we're tracing it out before we do that replacement. But the way that the console works here, I guess you do get that once you expand it.
Now, we can see that we're actually getting Joel's list of repos coming back instead of mine, because we've actually modified the URL that's being requested.
Now, we can get rid of that and we've already seen how we can react to the response data, which, in this case, we're just listing out.
But in an application, I've had times where maybe I want to simplify the data that's coming back or maybe I want to parse it into a different structure that's easier for my application to deal with.
Any sorts of modifications you want to make there, you can. The important part is just that you return that result from this function. The same thing here, you need to return that config, because other things down the promise chain need to have these new objects or even the same objects. You need to make sure that you return the correct things.
Now, one of the probably more common uses than what I've actually used in production is to handle these response errors and do something useful with it. In this case, just so we can see how this works, I've got a failed with, and then, rejection.status, and then finally, again...
In this case we're going to reject the rejection that we get, just so the promise chain acts properly after we call it. But if I were to, add an invalid URL here, and then go and rerun this, you can see that we now have our custom message here, failed with four status.
Now, you're probably not going to want to just give the status to your application, but what I've actually used it for is to detect authentication errors or session timeouts. If we actually go up here and add location to the list of things that we're injecting into this interceptor, we can then check this status...
If we copy that, we can say if rejection.status is equal to 403, then, go ahead and redirect to the login page. This is something I've actually used that's really helpful, because maybe somebody clicks on a link to an authenticated page that's somewhere else, or maybe they've just timed out, because they went away from their computer.
When they come back and try to restart their session, you want to be able to kick them back to that login page and knowing that rejection status is a good way to do that.