Now in the last lecture,
we finished implementing the model view controller pattern
at the example of our post related logic.
Now we can leave the MVC pattern again
and do some general improvements and refactorings again.
Because if we have a look at the post controllers JS file,
this is now still a pretty big file.
And there still is some redundant logic in there,
which we might want to get rid of to simplify that file
and avoid unnecessary code duplication.
And the first big thing that comes to my mind here
is this session usage for error management.
If we have some invalid input and we use the session
for storing information about that error
after we redirected.
That is something we do in a couple of places,
it takes up a couple of lines of code
and it's some unnecessary repetition here, I would argue.
The same, by the way,
goes for the general validation of input in my post routes,
where I also performed the same checks
and then the same updates of my session data
in two different routes.
And that's there for some code duplication,
which we can probably get rid of.
Now, I will get started with extracting that error data
from the session and setting a default data
if we hadn't any errors in the session.
For that,
I'll add yet another folder in the project.
And it is quite normal that as your project grows,
you work with a couple of folders to organize your code.
And we could give this folder a variety of names.
We could name it util or utilities since it stores
some utility functionalities,
or validations, since it will be involved with validation.
And managing that error data into session is,
of course, is also part of the validation process,
because we're doing that because some validation failed.
Still, I will go for the more generic util for utility name.
And in there, I'll add a new file,
which I named validation dash session JS,
because I want to store all the validation related session
related logic in there.
Now what could that be?
In the end, if we have a look in our get routes,
when we load a page and we check wherever we have errors
in the session,
which we want to use for pre-populating a form,
we always perform the same couple of steps.
We extract that potential error data from the session.
Then we check if we were successful extracting that.
And if we were not, we set some default data.
Then we clear the data in the session,
so that for subsequent requests and page reloads,
we don't see the same errors over and over again.
And then ultimately we pass that data to the template.
So these three steps actually can be cut here
and they can be outsourced into this validation
session JS file.
And there I'll add a new function,
which I will name get session error data,
since that is what I need to do here.
I go to my session and check for error data in it.
Now I'm relying on the existence of this request object
in there.
So therefore,
I assume that I do get it as a parameter value
and we'll have to make sure we pass in that request
when we call this function later.
Then, I perform the same steps as before,
reading data from the session
and clearing the data ultimately.
And then I returned my parsed session input data here.
Now I will, of course,
export this to make this available outside of this file.
And since I will soon add more to this file,
I will have more than one function in there soon.
I will actually export this in an object
so that we can group multiple exported functions together.
And here I'll use get session error data as a key.
And then the value is a pointer at this function.
And now in post controller, we can use that.
Here at the top where I also import my model,
I can now also import my session validation object
here by requiring util validation session.
So actually let's maybe name it validation session
here as well.
And then in this get admin controller,
I will call validation session
and call get session error data.
And what I'll get back is always such a session
input data object in the end,
or a session error data,
if you want to call it like this,
which I pass to my template then, using that same key name.
And with that, we're executing the same logic as before,
but we moved it out of the controller into a separate file
to make that controller a bit easier to understand
and a bit slimmer.
And I'll do the same in this get single post route.
Here, I also get my session error data
and hence, I'll replace that with that same line of code.
I copied that from the route where we worked in a second ago
and I'll then use this session error data for this template
as well.
Now, like that it wouldn't work though.
To make it work,
we have to make sure that we pass this request object
into this function because we rely on that.
So in both the places where I call get session error data,
I pass my request into that function.
Here in get admin,
and then also further down in get single post.
With that the result should be that we can still visit
the admin page.
And if I use the developer tools to get rid of the required
attribute so that I can submit this without a title,
though, that normally should not work,
but here it works because I removed required.
Then my server side validation kicks in
and I get this error message as expected.
The input I did enter was saved, but if I reload again,
everything is gone because we cleared that error data
from the session.
So that's the first step.
We're still getting that data from the session,
but we're doing it in a separate file.
Now, of course,
the other part that's also related with that
is that we write data to the session if validation fails.
For this, I got my validation logic here,
but then ultimately I'm also writing data to a session.
And I'll actually cut this logic here and move that
into validation session as well, in this separate file.
There, I'll add a new function which I'll name flash errors
to session.
Flashing simply means that it's on a session temporarily.
And here I put my data onto a session.
For this, I still need the request object though.
And I also need the data that should be flashed
onto the session.
Because I will always set has error to true,
but the message title and content,
that's not always necessarily the same,
especially if we have a look at the auth routes,
which we haven't really factored at all yet.
There,
we used different error messages for different routes.
So that should be settable from outside this function.
Hence, I'll replace this content here with
dot dot dot data.
You might remember this dot dot dot operator.
I did briefly introduce that early in the course as well.
That's the so-called spread operator
and here I expect data to be an object.
And when you use the spread operator on an object,
it simply takes all the key value pairs in that object,
all the properties of that object and adds them
as key value pairs.
So as new properties to that object
in which you use the operator.
So that will take all the key value pairs of data
and add them to this object, which is added to the session.
And then as a last step,
I actually also expect to get a third parameter value,
action, let's say,
and that should be a function that should be performed
after the data was stored in a session.
So here I will manually call request sessions save.
And then here, I pass action to this save method
because the save method takes a function
which it will execute after saving finished.
And I want to be able to receive that to the executed
function from the outside world,
so that we only performed that action, for example,
our redirect, after we saved the session.
And then last but not least,
I'll expose this flash errors to session under the same key
to the outside world.
Back in post controller JS,
that means that here in that failed validation,
I can use my validation session object
and call flash errors to session, pass in the request,
pass in the extra data.
In this case, a new object where I still have my specific
message, title and content, and then pass in the action,
which should be this redirection.
And I actually had the wrong code here before.
I did not wrap this into the save function before.
Now I will add a new anonymous function here in which
I redirect.
And it's this anonymous function,
which has passed as an action,
to this flash errors to session method.
So that it's this anonymous function,
which will be executed here after we saved.
So overall,
we still have quite a bit of logic here
in the post controllers JS file,
but we also were able to outsource some common tasks,
at least.
It is important that we still return there after,
so that no other code in there executes
if we made it into this block though.
So that should absolutely stay in that controller file
because if we would return inside of flash errors
to session, for example, that wouldn't help us at all,
because then we would just end the execution
of that function, but not of this controller function.
So return needs to stay here in the controller instead.
And now last but not least,
I also got some repeated validation logic.
I got the same checks here for updating a post,
as I do have them here for creating a post and therefore,
in my util folder, I'll also add a validation JS file,
which holds the core validation logic.
And here I'll add a new function.
Name it post is valid because this function
should answer the question whether a post is valid
and I expect to get the title and the content of a post
as a parameter here.
And then I will actually grab this check here,
copy that and returned that like this,
this will overall evaluate to a Boolean value, remember.
However,
I need to invert it because the function is named
post is valid, so it should return true if the post is valid
and the post would be valid if entered title is truthy.
So no exclamation mark and entered content is truthy.
So no exclamation mark and the trimmed entered title
is not empty.
And the trimmed entered content is also not an empty string.
If all these conditions are met, then a post is valid
and therefore, that is a function which now contains
all the validation logic.
And we can then use it in a another file
so that we don't have to repeat that logic
over and over again.
And then here,
I will also export an object,
since I will add more validation logic to that file soon.
And we can return or export post is valid like this.
Now to make this work here, this post is valid function.
We now of course have to use title instead of entered title
and content instead of entered content,
because these are the parameter names I'm getting here.
Alternatively,
you would have renamed these parameters
and then back in post controller where we want to find out
if a post is valid,
instead of having our condition here,
which of course also works, but to save some space,
we can now execute this function,
which I defined in a separate file.
For this, I'll just include it here in this file.
I'll name the constant validation,
and then require util validation like this.
And then in the place where I want to validate, like here,
I will just execute validation dot post is valid,
execute this as a function and pass the entered title
and the entered content as parameter values.
And here, I want to know if that's not valid.
So here I will add an exclamation mark.
And now we execute this function.
This function then will return a Boolean
and we use that Boolean in this if check,
so that we were able to outsource the overall
condition into a separate file.
Now here in create post,
we can now also use our newly added method
for flashing the error data onto a session
and use the validation session object to call flash errors
to session, pass in the request,
our object with extra data,
which contains the message title and entered content,
and then get rid of this part here.
And then as a third parameter value,
pass in an anonymous function,
which is the to be executed action,
where I actually will redirect.
And then if we go down to updating a post again,
here, I can also, again, use validation dot post is valid.
Execute this, pass in the entered title
and entered content, check for the opposite,
since we want to make it in there if the post is not valid
and we already refactored the flash it to the session
logic before.
Now, we did refactor the entire validation logic
and added these extra methods for getting data
out of a sessions, but one tiny bug I introduced with that
is that if we do now try to view and edit an existing post,
we load an empty form.
It's not pre-populated with the existing post data.
The reason for that is that in get session error data,
I do always set title and content to an empty string
if we don't have any error data in the session.
And whilst this is correct for a new post,
this is not correct for updating an existing post.
Instead, I want to initialize this with existing titles
and contents.
Hence I will tune this get session error data function
a little bit and accept the default values here.
That's a parameter name we could use,
which should be an object with any default values
we want to set.
And then we'll again,
use the spread operator to spread that object
of default values into this new object I'm using here.
So we'll use all the key value pairs in default values
in this object.
And then in the post controller in the places where
I use get session error data,
I pass in that second parameter value
where I do set my starting title equal to post dot title
and my content to post dot content.
And on the other hand, when we create a new post,
then that starting content or the default values,
of course will be these empty strings.
So then I set title equal to an empty string
and content equal to an empty string.
But now we have different default values
for the different pages for the different routes we have,
whilst still outsourcing the general shared logic.
And with that, if I view and edit this,
it is now pre-populated correctly.
The same goes for creating a new post where it is empty
as expected.
And that now were a bunch of refactorings.
And with all those refactorings,
this post controller file is way leaner.
Now, the last thing I want to do in here is related
to the CSRF token.