In the previous lesson,
we have learnt about how file uploads are
supported through the multi-platform data approach.
In this exercise, we're going to make use of the Multer module,
which we referred to in the lecture to enable our express server
to support uploading of image files into our server site.
They will store these images files into the public/images folder.
This images would be useful within our application when we supply
images for the various dishes or the radars or the promotions,
that we have constructed in our REST API server.
To get started with this exercise,
the first step of course,
is to install the Multer module so at the prompt type npm install
multer minus minus save and at the moment I'm using multer 1.3.1 in this course.
So once we have installed the multer module,
let's go to our project and then implement a new route that enables us to upload files.
Go into the project in the routes folder,
let's add a new file named upload router.js.
This router, express router that we're going to implement here,
is the one that is going to support the uploading of the files.
So, in the upload router let me just go to
the dish router and copy these first few things from the dish router
because we're pretty much going to set up
similar structure in our application or the upload router.
So, let me copy that part and then we will edit that.
So, in the upload router,
I don't need mongoose so I'm going to remove mongoose and I don't need the dishes either.
So, those two would be removed and after that
we need to express body parser and authenticate.
Now, I'm going to require the multer module here.
Once we include the multer module,
now this router I'm going to call this as upload router.
So, will say upload router use body parser and
then this one but the upload router and again,
remember to say module exports, upload router here.
So, for the upload routers route,
we need to add the various methods.
I'm going to do that a little bit later but before that let's set up
multer to enable us to upload the files.
Now, by default, multer can be setup by simply using multer within our application,
but I'm going to do some configuration of multer in
this exercise so that we're going
to customize the way multer handles the upload of the files.
So, to use the multer,
one of the options that multer takes is for the storage.
So, multer provides this disk storage function which
enables us to define the storage engine and in here we can configure a few things.
Now, if it is just a matter of configuring the destination,
you can simply say dest colon,
and then specify the destination folder within which the uploaded files will be stored.
But here I'm going to do some further configuration for the multer module here.
So, this is where I'm going to use the multer disk storage support.
Inside the disk storage,
I can define a couple of options here.
The options that I'm going to define are going to be
destination and the second one is file name.
So, two configurations that I'm going to supply to the disk storage.
The destination as you would expect,
allows me to configure the destination and this takes
as a configuration here a function here.
So, the destination is configured as a function here.
This function will receive request and also an object called the file,
which contains information about the file that has
been processed by multer and also a callback function.
So, cb is the callback function.
So, here for the destination,
I'm going to say cb null,
the second parameter is the destination folder,
which can be expressed as a string where the files will be stored.
So, in here, I'm going to supply the destination as public slash images.
Because in this exercise I'm going to support image uploads.
So, that is the part that I'm going to specify here, so image upload.
So, the callback function as you see takes two parameters.
The first one is, of course,
the error which in this case I'm going to set it to
null and the second one is the destination folder,
where my images are going to be stored.
So, I can configure that by saying public slash images.
So, in the images folder,
the files that I upload will stored.
For the file name also,
it gets the three parameters,
request message, file and the callback function.
From configuring the way the callback function is called,
we can specify information about the file name.
So, for the callback function I would say cb null and there's no error here.
Then the second one insists on the file name,
that is going to be used for the specific file that has just been uploaded,
how it is going to be stored.
So, this file object that I obtained here,
supports a set of several properties on it.
One of the properties is called, original name.
So, the original name essentially,
gives us the original name of the file from the client side that has been uploaded.
I insist that, when the file is saved on the server side,
the file will be given exactly the same name
as the original name of the file that has been uploaded.
So that I can know that I'm uploading
exactly the same file and on the server side when
the file is uploaded will stored with the same name.
Now, if you don't configure this then,
multer by default will give some random string
as the name of the file with no extensions.
So, that may not be something that you would be happy
about using in this particular exercise.
So, that's why I'm explicitly configuring saying that,
the file should be stored with the original name of the file that has been uploaded.
We will again encounter this file object in
a bit more detail and see how we
can make use of information from the file object a little bit later.
In addition, I can also specify a file filter here for the multers configuration.
The file filter will enable me to specify which kind of files
I am willing to upload or that I'm willing to accept for uploading.
So, for doing this I will set up another function called
const image file filter
and this one I will define the function in a minute.
Now, for this, I can also save this as
const storage because we have been using const for everything,
so, I'll just say const storage.
For the image file filter,
I'll say const image file filter.
Again, it receives three parameters request,
object, the file object which contains the information about
the file that has been uploaded and the callback function here.
Through the callback function,
I will pass information back to my multer configuration that
enables me to specify how I'm going to store this information.
So, this is going to be an arrow function here.
Inside this arrow function what I will check for is that,
I'll say if not file original name match.
So, the original name is a string here.
So, I'm trying to see if there is a match for that string by saying,
inside here a regular expression.
So, the regular expression I will specify it as slash,
backslash dot and then,
the options that I'm going to specify is jpg
or jpeg or
png or gif.
So, that is how I specify the regular expression there.
To say that okay,
if the file's extension contains jpg or jpeg or png or gif,
then I will treat that as an image file and I will be willing to accept those files.
So, that is what we are testing here.
If that is the case,
that is if the file extension does not match any of these things, so,
that's why we're seeing not then we'll say, return cb.
Then, notice that, the cb the first parameter would be an error.
So, I will return a new error
saying you can upload only image files.
So, we are insisting that the only files that they will
accept are image files and the second parameter would be false.
Because we are supplying the error as the first parameter,
the second parameter is set to false.
The otherwise is saying cb null true.
So, which means that the file that is trying to be
uploaded matches the pattern and so It is an image file,
and so we're willing to let it be uploaded.
Two configurations that we are going to supply to that multer module.
How do we configure the multer module for use within our application?
This is where I will declare const upload
as multer and then I would specify in brackets that options here.
I can specify the storage as the storage function that I've just defined here.
This storage function as the first parameter,
and the second parameter is a file filter.
A file filter is a method that enables me to specify
which kind of file that I'm willing to accept and then so I will say, image file filter.
Just toggle the word wrap,
so that you can see the entire line here.
So, it say you can upload only image files and then for the multer,
I am configuring the image filter, that's it.
My multer module is now configured to enable me to upload the image files here.
Then let's now go ahead and configure the upload router.
For the upload router,
I'm going to allow only the post method here.
So the get, put,
and delete methods will not be allowed on the upload router endpoint.
To help me do that,
I'll go to the dish router and then recall that we had the put configured here already.
I'm going to copy that and then come to
the upload router and then I will paste that information here.
We'll say, if it is a get operation then I am not going
to support that on the endpoint would be imageUpload.
The get will not be allowed,
and similarly the put will not be allowed,
and also delete will not be allowed.
I'm not going to support any of these operations, so put, delete.
These three will not be allowed.
The only method that I'm going to support is the post method.
For the post method,
we're going to do this authentication all the way up to that point.
I'm just going to copy that in there,
close that endpoint and for the post.
When a file is posted,
how do we handle this post?
To handle the post here,
I don't need the next for this.
Now, in addition to the authenticate verifyUser and authenticate verifyAdmin,
on the same line I will configure the upload.
So, recall that I had configured upload by using multer here.
So, I'm going to make use of the upload which
supports a function called as upload.single.
This single function takes as parameter.
The name of the form field which specifies that file,
you will see that in a short while.
This form field I will name it as imageFile here.
Upload single means that it is going to allow me to upload only a single file here.
That single file will specify in the upload form from the client side
in the multi-part form upload by using that name there.
When the file is obtained in the code,
if I come up to this point,
this upload will take care of handling the errors if there are any,
if the file is not properly uploaded and so on.
When you come up to this point,
the file would have been successfully uploaded and
so you need to handle the uploaded file.
At this point, we will say res.statusCode is
200 and then res.setHeader Content-Type,
'application/json'. What I'm going to do here is that,
we will pass back this req.file object from the server back to the client.
This req.file object will also contain the path to the file in there and that path can be
used by the client to configure any place
where it needs to know the location of this image file.
For example, if you are trying to upload a dish
to the server side and the details of the dish to the server side,
you might upload the image to the server and then
you get back the URL of that image and then you maybe
including the URL of that image into the json object that describes the dish.
Then upload the dish json document to the server side.
Then the req.file is passed back to the client,
the req.file as you will see when we run this server,
the req.file contains a lot of information about
the file that has just been uploaded and so I'm going to
examine that to obtain information about the file that I just uploaded.
This is how we're going to be configuring the post method there, that is it.
My upload router is all ready to accept uploads of the files.
Now, all that I need to do is to go to app.js and then configure the upload router.
So, going to app.js
We already have all these routers.
So, let me just copy their leaderRouter and then
configure this as uploadRouter.
So, this is in the uploadRouter file here.
So, we'll configure the uploadRouter and then going down below here,
we will now configure the imageUpload endpoint.
So, the imageUpload endpoint allows me to upload the file.
So, this would be uploadRouter. That's it.
My application is now configured to accept file uploads.
So, let's save the changes and then go and take a look at how our application works.
Going back to the Terminal,
now make sure that you have your MongoDB server up and running in
one of the Terminal tabs or in one of the command Windows.
In the other window,
let's start the server.
Once our server is up and running,
we will go to Postman and then send or rather upload a file from Postman.
So, as I mentioned,
to upload a file,
you will be using the multipart/form-data.
So, first, let me log myself in.
So, I will do a post on local users login,
and I will log myself in as the admin because
only the admin can upload their files there.
Recall that your server is now running at the secure port.
So, we'll say https://localhost:3443,
and there's no authorization in here.
So, let me turn off the authorization in here and then send the request to the server.
So, in Postman, if this is happening,
that it says could not get any response,
this is because you're now running the secure server.
So, in that case,
Postman will not accept the self-signed certificate that is coming in.
So, in that case, open settings here and in the settings,
under the general settings field,
you will see this SSL certificate verification.
Turn that off so that your Postman will be willing to accept
the self-signed certificate that we have installed on the server-side.
So, this is how you will be able to contact your server at
the https://localhost:3443 user login endpoint.
So, when we try to login now,
you will now see that your post request has been
successfully accepted by the server
and then the server replies with the token information.
So, again, to ensure that Postman allows you to contact the secure server,
click on Settings and under General,
turn off the SSL certificate validation.
So, once you login,
let's copy the token here.
So, I'm going to copy the token here.
Now, let's try to upload the file.
To upload the file, as you noticed,
we need to upload this file at localhost:3443,
and the endpoint is imageUpload.
For doing the imageUpload here,
in the Header, we need to configure the authorization.
So, we'll configure authorization,
and then you'll say,
"Bearer", and supply the a token that we have obtained.
So, keep a copy of the token somewhere and copy in the token into the Header.
In the Body, to upload a file,
we will use this form-data.
So, this is what allows you to do the multipart/form-data here.
So, when you click on the form-data,
here you can supply that file here that you wanted to upload.
So, when you click a new key here,
use this key as imageFile.
Recall that when we configured the post method on the uploadRouter site,
we specified saying upload single an imageFile.
So, that's the same key that you're going to be using here.
Then, when you give the key,
then the second part,
you will set this from Text to File here.
So, this is what allows you to specify the file as the value for this particular key.
So, then you will see this button coming up saying, "Choose Files."
So, you can open that and then select a file that you want to upload.
So, here, I'm going to go to my,
I have a file in one of my folders here.
So, I'm just going to go into assets images,
and then we'll just upload a PNG file from here.
So, you can say,
"Upload the specific file."
So, as you recall,
we configured our server to only accept imageFile.
So, we'll say, "Upload that particular file."
Then when you click on the Send button,
so notice that in the body,
you have to configure this with form-data.
So, the multipart/form-data, and then the key is the imageFile,
and the value is the file that you just selected,
and then click on the Send button.
So, when you click on the Send button,
the file will be uploaded to your server-side and
then the server will reply back with this object.
So, this is what is contained in the
req.file object that is there on the request object here.
So, this req.file, as you see, contains a fieldname.
Fieldname is imageFile.
So, notice that this is exactly the same as this one here.
The originalname, so notice that the originalname expression contains alberto.png,
which is the file that I uploaded.
Now you can see why when I configured
the storage and the filename, I set file.originalname.
So, this is what is going to be used there.
You can see the encoding type,
and the mimetype, and the destination,
which folder the file has been put into,
and the actual path of the file here,
the relative path from the root of the server folder here.
So, this path indicates where the file is accessible on the server-side.
So, if you are configuring the details of a dish or a leader, for example,
you would simply use the image property of the leader to images/alberto.png.
Public should not be used anyway because the public folder is
the one that is acting as the root folder for our server.
So, you just need to supply these images.alberto.
So, from this path that you obtain,
once the file is successfully uploaded,
extract this part and then use that for the image in
your JSON document that describes the specific leader.
So, that's the way we upload a file.
Now, to convince you that the fine actually got uploaded,
let's go to our project.
Going to our project,
in the public folder,
you can now see that there is an images sub folder there.
In the images sub folder,
you can see the alberta.png file uploaded in there.
Now, we can upload more imageFiles into our server-side.
Now, if you try to upload a non-imageFile,
you would see that the server will not accept
a non-imageFile and then will reply back saying,
"Cannot accept the non-imageFile."
So, this is how we will configure our express server
to accept uploads of imageFiles from our client-side.
With this, we complete this exercise.
In this exercise, we have seen how we use
the meta module to configure our express server to
accept file uploads on a /imageUpload Rest API endpoint.
When we post to the endpoint,
the file gets uploaded to a specified folder on the server site.
With this, we complete this exercise.
This is a good time for you to do a git commit with the message 'file upload'.