Hello, everyone, and welcome back.
In this lesson, we are going to create our own observable similar to the interval observable or the
click observable that we have here.
And we are going to do that Using a practical example, we are going to do a call to the back end.
We're going to fetch a list of courses that we are going to be displaying here on the courses screen.
This will give us a great insight into how observables are built and is going to help us a lot to introduce
all the rxjs operators that we are going to be introducing after this lesson.
Before continuing, let's take a moment to clear here the initialization method of our component so
that we don't have these logging messages in the console as we develop our Http observable, the data
that we are going to be loading into our application is coming here from our rest API backend running
on Port 9000.
So make sure you have it running at this point in the course.
Let's have a look at the data that we are going to be fetching from the backend.
We are going to switch here to a larger window and we are going to access here our rest API server and
we are going to access here the URL slash API slash courses.
So as you can see, we have here a Json payload that is getting returned to us containing here a list
of courses if you want to have your Json payload formatted like we have here on the screen, you can
install a Chrome plugin such as, for example, Json formatter that we are using here.
Let's now go back to our application and see how we are going to fetch this data under the form of an
observable that is going to emit one value containing this complete payload and then it's going to complete.
Let's first see how we are going to be making this call to the backend.
We are going to be using directly the browser fetch API.
So if we call fetch and we pass it a URL, so we are going to pass the URL slash API slash courses and
this is going to get us back a promise.
This promise is going to be evaluated successfully if the request succeeds and it's going to fail if
the request fails due to some fatal error, such as, for example, the network is down.
Notice that a promise is very different from an observable.
A promise will get immediately executed once we define it.
This is unlike the observable that when it gets defined, it does not trigger any requests.
It will only trigger the request in response to a subscription.
So let's see how we are going to turn this http call to the backend into an rxjs stream.
Let's see how we are going to create an observable that represents this Http request.
We are going to be creating a custom observable for that and we are going to be using the observable
dot create method.
This method will allow you to create an observable from scratch.
And this is how all those observables that we have seen before, such as, for example, interval or
timer, are created by calling observable dot create.
Now we are going to take the output of this call and we are going to assign it to a variable.
So let's remember the output of this is going to be an observable that is going to model here, this
network call to our backend.
In order to create the observable, we need to pass here to the create method a function.
This function is going to implement the behavior of our observable.
In this case, it's this function that is going to do the network fetch.
So this function takes one parameter which is known as the observer.
The observer is what is going to allow us to emit new values, error out the observable or complete
the observable.
So the observable here does not allow us to emit values on its behalf.
Instead, we can only subscribe to it and get values from the stream of values.
The observer, on the other hand, should be kept private here to the implementation of the observable.
And this is what will allow us to either emit a new value for our stream calling next or error it,
calling error on it, or even complete it.
Calling complete.
The observer is what we use internally to implement the observable.
This function here that takes as argument.
The observer will only be called when we subscribe here to our Http observable.
So when that happens and only when that happens, then we are going to be calling here fetch and we
are going to be hitting here this slash api slash courses URL.
What will happen if the request is successful.
Let's see.
We are going to apply here then, because this is a promise and we are going to get back here.
The Http response that came back from the backend.
Let's have a look at what we have in this response.
So we have a body.
We have here an okay flag that is going to tell us if a fatal error occurred or not.
And we have here a status code.
We also have here a Json method that returns a promise containing the response payload.
So if we want to retrieve the response body containing all the courses from this response payload,
we need to call response dot Json.
This is going to get us back a promise.
So we are going to return it and this is going to be further evaluated down this promise chain.
And what this means is that if we now call Dot, then here we are going to be getting here the Json
body of the response and not the response object itself.
We now have here the Json payload that we were looking for.
So what we're going to do now with this Json payload is we are going to emit it as the value emitted
by this observable.
We are going to call the observer and we are going to call the next method on it.
So this is the method that is used to emit values in the observable.
Now, after emitting this initial value, what we want to do now is to complete the observable because
nothing else is going to be returning from the backend.
So we already know that we won't be able to emit any further values.
So we are going to be calling here observer dot complete.
And this way we have terminated our Http stream.
Now in this initial implementation, let's also cover the case when a fatal error occurred, such as,
for example, a DNS error or a network error, let's say that a network is down.
So in that case, in that fatal error scenario case, we are going to be calling here the catch method
here in our promise chain.
We are going to get back here an error and we are going to now error out our observable.
We are going to call observer dot error and we are going to pass it.
The error that we just got here in this catch callback.
So like this, we are making sure that we are respecting the observable contract and then we are either
completing the observable or we are calling error here.
Notice that when we are creating here our own observables, it's up to us to make sure that we respect
and understand the observable contract.
So if we would create here another value in this observable here by calling next after calling complete,
we would be essentially breaking the observable contract.
So there is no way what our program would do in this scenario.
So very important if you are creating your own observables like we are doing here, please make sure
that you follow the observable contract.
This is absolutely essential in order for all the other operators that we want to combine with Http,
for example, to work.
So we now have here an initial implementation of our Http observable.
We are going to be coming back to this implementation and add unsubscription logic and error handling
more than what we have here.
But right now we already want to demonstrate that this is working and that our Http observable is indeed
working as expected.
Let's try this out.
The first thing that we are going to do is we are going to try to execute our program without subscribing
to this observable.
So let's refresh the application and run here.
This component initialization method.
And as we can see, nothing is happening in the console.
And also no Ajax requests were made.
This is just a request made to our development server to enable the hot reloading mode.
But this is not the request made here to slash API slash courses just like it happened before.
This observable here is just the definition of an Http stream, but we have not created a concrete instance
of that stream.
In order to do that, we need to subscribe to this observable.
Let's add here the multiple callbacks to this Http subscription and see how this is working in practice.
So here we are going to be getting here the courses, so let's print them out here to the screen.
We will also be providing here an error handling callback and because we are not expecting any error
at this stage and we will be revisiting error handling in the future in this course, we are going to
be providing here an empty implementation for this callback.
We will also be providing here a completion call.
Work so that we can confirm that our stream is indeed completed in order to make our code a bit more
readable.
Instead of passing in here this empty callback, we can also refer here to the Rxjs Noop function.
So Noop stands for no operation.
That is essentially the same thing that we had here before.
It's just a bit more readable.
So with this in place we are going to reload our application and have a look at the console to see what
we have here this time around.
So as you can see, we are printing out here an object and if we hit here, this drop down arrow, we
are going to see that indeed this object is the payload containing here all the courses.
This is not yet under the form of an array and we are going to transform it into an array by using the
Rxjs map.
Operator.
That's going to be the first operator that we're going to use in the next lesson.
After emitting here.
The value of the course is to the console via here.
This success callback we are going to be completing here our Http stream.
So as you can see, our Http stream is working as expected and our Http observable is indeed respecting
the observable contract.
Now you might think why go through this work of transforming a promise based fetch call that already
fetched our data into an observable?
So what is the advantage here?
The advantage is that we can now use all the rxjs operators to easily combine our Http stream with other
streams, such as, for example, click handlers, timeouts, other Http requests.
We have a whole world of operators that makes it really simple to combine streams of values.
Let's then give a concrete example of one of those operators.
We are going to be using the Rxjs map operator that is going to take the Json payload of the response
and it's going to transform it into an array of courses.