As we discussed in the last video let's implement this custom air abstract class.
This is going to extend the base air class we're then going to make sure that request validation air
and database connection air extend custom air instead of the air built in.
So let's get to it back inside my editor off on the air directory.
I'm gonna make a new file inside they're called Custom air Dot T S then inside of here I'm going to
declare a new class new abstract class to be precise so abstract class custom air and this is going
to extend or extends a built in air class then inside of here we're going to list out all the different
properties that must be defined by any class that extends this very similar to how an interface works
remember we write out interfaces and we try to satisfy the interface same thing with abstract classes
or the way in which we write out these properties at subclasses must implement is just slightly different.
We're going to write out abstract status code number.
So this is saying that if you're going to extend customary you gotta have a status code property and
it must be a number by writing out abstract right there.
That's what's saying that a subclass must implement this thing.
So we could test this out right away.
We can say hey let's have a new class right here goes something like not found error and we'll try to
extend estimate right writer way we'll get an error.
It says hey you need to make sure that you implement that status code property.
So if we put inside of your status code for a before it goes away.
So again very similar in nature to a interface but we're using a class instead because that's going
to allow us to carry actual class definition over to the javascript world down.
Next up we will define a constructor.
The only reason we are defining a constructor is to make sure we can put in that special little line
of code that we've seen once or twice.
Now that is required anytime that we are trying to extend a built in class.
So it's that same thing that we wrote out over inside of both database connection error and request
validation error.
Is that object set proto type of thing so back inside of our customer abstract class and make sure I
copy one of those over and we'll make sure that I update the name of the class right there as well.
To customer because we are defining a constructor.
We do have to define super like so.
Then after that let's set up our other method or the other requirement of anything that wants to be
a customer.
So I'm gonna say you must have an abstract method of serialize errors so we're not actually defining
a method here instead we are defining a method signature.
So we're saying that to extend a customer you have to define serialize errors and it must return something
that is going to be an array of objects and each object must have a message that is a string and optionally
can have a field that is a string as well and there you go
so now we can go back around to our other two custom classes though database connection area and request
validation error.
We're gonna make sure that they extend customer and that's going to put in this requirement that they
must implement a status code and serialize with the appropriate signature they'll first go over to database
connection error at the very top.
I'm going to import custom air from customer
now rather than extending the air built in class.
We want this thing to extend custom air like so.
So now if we ever put any type of inside of here if we ever forget to implement status code we're gonna
get there.
If we ever misspell status code we'll get in there.
If we ever return something from serialize theirs that does not have the correct structure like just
m.
We'll get in there.
And so again this is all about making sure that we are implementing these custom air classes correctly
so now we can repeat that same process inside of request validation error as well.
So at the top I'll do an import SDM air from customer and again I'll update that extend statement to
custom air like so.
So again if I forget to implement status code it gets an error if I ever make a typo inside of serialized
errors we get an error as well.
Okay.
Let's say that this is a definite improvement.
It's gonna make sure that we always implement these air classes 100 percent correctly.
All we have to do is remember to import custom air.
We build a class we extend customer and then typescript is gonna take it from there typescript is gonna
tell you hey if you want to be a customer you gotta have that property you've got to have serialize
theirs and you won't need anything else.
Any other information to understand how to do this stuff or how to actually build out of custom air
because typescript is going to guide you along the way.
All right.
So now there is one less very quick thing I want to take care of.
This is a very small oversight inside of customer.
We are extending the air base class as a reminder.
Normally when we create a new air or throw in air we'd write out something like new air then we put
the reason for the air inside of here.
So generally whenever we create an air instance we pass in a string describing exactly what just happened.
As we've discussed a billion times now we didn't really want to rely upon that string too much for trying
to communicate any information that eventually will get sent back out to the user.
However these error messages or whatever string we put inside there will still be printed out inside
of our server logs.
And so it kind of would be nice if something goes wrong inside of application to still have some kind
of actual string something and says hey for logging purposes here's what just happened so to make sure
that we still have that behavior or to essentially have something equivalent to it.
This right here we need to make sure that whenever we create an instance of something that is an error
we pass in the error message or this string into that super function right there when we call super
right there.
That's equivalent to calling new air.
More or less.
So I got to say in addition to being a customer in addition to having a status code and serialized errors
and all that stuff you also have to make sure that you provide a message that is a string.
We'll just take that message and pass it on through to the air.
So now when I saved that we're going to get an error from our database connection error and request
validation as well because they want to see a string or a default message being passed in.
So again this is just for logging purposes so we can put something inside of here that really just makes
sense to you and I.
So we could see something inside of here like air connecting to D.B. again really just duplicating the
reason right there and then same thing for request validation we could put in something like invalid
request parameters.
Again this is really just for logging purposes.
This is never gonna be sent out to any of our users or anything like that.
All right.
Very last thing I swear I know said that so many times by really promise at this time last thing we're
going to do we're going to reap the benefits of all this air stuff inside of our air handler middleware.
Now rather than writing out these separate if statements and watching for every possible custom air
class any customer we build should be technically an instance of the custom air class so we can change
these if statements and condense them down to just one single check at the very top.
I'm going to delete those two import statements or the very specific customers we put together and I
will replace it with customer from up one directory heirs custom air.
And now we can go down to just one if statement so going to delete the second one.
And we can update the instance of check to be custom air instead and that's it.
So now if we throw any air from a request handler that is extending customer our area handling Middleware
is going to handle it appropriately.
It's going to take the status code off the custom error instance.
It's going to call serialize errors and this is going to 100 percent guarantee as best as we possibly
can that whenever we send a response back from any root handler in any of our services we're always
going to have a very consistent structure going back to something that looks like this right here but
of course we did end up with message and built like so.
So we'll always have guarantees as best we can.
Once again that we will end up with this structure.
All right.
Once again I know this area handling stuff has been really nasty but we're finally done with it.
One of the reasons that we spent so much time on this error handling stuff is that it turns out that
there's actually a couple other locations or a couple other things you have to do in all these micros
services that's going to be relatively similar in nature to what we just did.
So we have tried to essentially condense down a ton of functionality make it reusable in nature and
we also try to build up some type guarantees through the use of this abstract class right here.
There are going to be some other scenarios some other things we're going to go through where we want
to guarantee functionality again as best we can across all of our different services.
Most specifically this really comes down to a lot of that event handling stuff that we did manually
back on our last project so we're gonna go through a somewhat similar process when we start to build
out all the event handling stuff this time around.
And again that's why I wanted to go through this kind of deep dive on the air handling stuff make sure
it was clear about why we agreed the abstract classes why we were extending a base class why we wanted
to guarantee the structure of data coming to the middleware and all this good stuff well before we stop
we probably should do just a very quick test here why not.
I can go over to post man I'm going to try to sign up with an invalid e-mail get looks good and I'll
put in a valid e-mail and I get air connecting to database awesome.
This looks good.
Let's take a pause right here and continue in just a minute.