title
Uploading an Image | Creating a REST API with Node.js

description
We're already storing a lot of data on our database but what about files? Let's take a closer look! Join the full Node.js course: https://acad.link/nodejs Check out all our other courses: https://academind.com/learn/our-courses ---------- Learn Node.js in our comprehensive 30h+ course: https://acad.link/nodejs More about Multer: https://github.com/expressjs/multer Parsing Binary data in Node.js: https://stackoverflow.com/questions/16598973/uploading-binary-file-on-node-js Source Code: https://github.com/academind/node-restful-api-tutorial/tree/09-image-upload ---------- • Go to https://www.academind.com and subscribe to our newsletter to stay updated and to get exclusive content & discounts • Follow @maxedapps and @academind_real on Twitter • Join our Facebook community on https://www.facebook.com/academindchannel/ See you in the videos! ---------- Academind is your source for online education in the areas of web development, frontend web development, backend web development, programming, coding and data science! No matter if you are looking for a tutorial, a course, a crash course, an introduction, an online tutorial or any related video, we try our best to offer you the content you are looking for. Our topics include Angular, React, Vue, Html, CSS, JavaScript, TypeScript, Redux, Nuxt.js, RxJs, Bootstrap, Laravel, Node.js, Progressive Web Apps (PWA), Ionic, React Native, Regular Expressions (RegEx), Stencil, Power BI, Amazon Web Services (AWS), Firebase or other topics, make sure to have a look at this channel or at academind.com to find the learning resource of your choice!

detail
{'title': 'Uploading an Image | Creating a REST API with Node.js', 'heatmap': [{'end': 738.366, 'start': 712.179, 'weight': 0.786}], 'summary': 'Tutorial demonstrates implementing file upload for product images using multi-part form data with the malter package in node.js, creating and fine-tuning product data, and updating data retrieval and storage while handling file uploads in express, resulting in an efficient backend file storage and retrieval process.', 'chapters': [{'end': 394.504, 'segs': [{'end': 186.905, 'src': 'embed', 'start': 131.417, 'weight': 1, 'content': [{'end': 141.444, 'text': 'now, if we accept a different kind of body, namely form data, to be precise multi-part form data, then this changes.', 'start': 131.417, 'duration': 10.027}, {'end': 143.445, 'text': 'then we can use this form data.', 'start': 141.444, 'duration': 2.001}, {'end': 155.453, 'text': 'object. javascript offers us, or you automatically get, when you submit a form, to submit both fields where we have data, like names or email addresses,', 'start': 143.445, 'duration': 12.008}, {'end': 160.697, 'text': 'and files where we have well the file, and this is the approach i want to use here.', 'start': 155.453, 'duration': 5.244}, {'end': 170.461, 'text': 'Now, to be able to read such incoming requests which hold form data, which is just a different content type, I need a separate package.', 'start': 161.757, 'duration': 8.704}, {'end': 176.163, 'text': 'So I will install it with npm install dash dash save and the name of the package is Malter.', 'start': 171.021, 'duration': 5.142}, {'end': 186.905, 'text': "now, malter is simply a package that, like body parser, is able to parse incoming bodies, but here we're talking about form data bodies.", 'start': 177.043, 'duration': 9.862}], 'summary': 'Using multer to parse incoming form data in javascript for submission', 'duration': 55.488, 'max_score': 131.417, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY131417.jpg'}, {'end': 294.899, 'src': 'embed', 'start': 241.621, 'weight': 0, 'content': [{'end': 248.027, 'text': 'Now this specifies a folder where Malter will try to store all incoming files.', 'start': 241.621, 'duration': 6.406}, {'end': 256.916, 'text': "This folder, of course, isn't publicly accessible by default, so we'll probably have to turn it to a static folder.", 'start': 249.449, 'duration': 7.467}, {'end': 269.726, 'text': 'so what we can do is we can go to our app.js, where we initialize our whole app, our express app, and set this folder up to be statically accessible.', 'start': 257.637, 'duration': 12.089}, {'end': 276.232, 'text': "we'll do this in a second step, though for now let's stick to implementing the upload functionality and see if that works as it should.", 'start': 269.726, 'duration': 6.506}, {'end': 282.102, 'text': "So we initialize Malter and we're saying hey, store all files in this place.", 'start': 277.358, 'duration': 4.744}, {'end': 286.645, 'text': 'Now we want to use it on this post route here.', 'start': 283.102, 'duration': 3.543}, {'end': 294.899, 'text': 'How do we do that? you actually can pass an argument prior to the function where we handle the incoming request.', 'start': 286.885, 'duration': 8.014}], 'summary': 'Specify folder for storing incoming files and make it statically accessible in app.js, implement upload functionality.', 'duration': 53.278, 'max_score': 241.621, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY241621.jpg'}, {'end': 352.122, 'src': 'embed', 'start': 323.187, 'weight': 4, 'content': [{'end': 325.509, 'text': 'for us, single is interesting.', 'start': 323.187, 'duration': 2.322}, {'end': 329.572, 'text': 'single means that here we will get one file only.', 'start': 325.509, 'duration': 4.063}, {'end': 338.778, 'text': 'so it will only try to parse one file and by just passing upload single here in front of this handler, it will parse that file.', 'start': 329.572, 'duration': 9.206}, {'end': 343.101, 'text': 'you here also need to specify the name of the field that will hold the file.', 'start': 338.778, 'duration': 4.323}, {'end': 348.981, 'text': "i'll name it product image here like this Now, with that we should be able to use that file in here.", 'start': 343.101, 'duration': 5.88}, {'end': 352.122, 'text': "And let's start simply by simply outputting it.", 'start': 349.641, 'duration': 2.481}], 'summary': "Using 'single' parameter for parsing one file, 'product image' field holds the file.", 'duration': 28.935, 'max_score': 323.187, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY323187.jpg'}, {'end': 403.229, 'src': 'embed', 'start': 373.313, 'weight': 5, 'content': [{'end': 378.096, 'text': 'Where I set up the destination uploads, the leading slash turns this into an absolute path.', 'start': 373.313, 'duration': 4.783}, {'end': 382.938, 'text': "So now it would try to create this in my root node modules folder, which I of course don't want.", 'start': 378.316, 'duration': 4.622}, {'end': 386.66, 'text': "So let's now restart npm start and now it's working.", 'start': 383.559, 'duration': 3.101}, {'end': 391.383, 'text': 'So turn this into a relative path by not specifying a leading slash here.', 'start': 386.94, 'duration': 4.443}, {'end': 393.064, 'text': 'with that.', 'start': 392.603, 'duration': 0.461}, {'end': 394.504, 'text': "let's simply try it out.", 'start': 393.064, 'duration': 1.44}, {'end': 403.229, 'text': "let's post a new product here, let's go to body, and now this will fail.", 'start': 394.504, 'duration': 8.725}], 'summary': 'Setting destination uploads with absolute path caused an issue, resolved by using relative path.', 'duration': 29.916, 'max_score': 373.313, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY373313.jpg'}], 'start': 2.805, 'title': 'Implementing file upload in node.js', 'summary': 'Focuses on implementing file upload for product images using multi-part form data with the malter package in node.js, as an alternative to accepting binary data only. it also explains the process of implementing file upload functionality using malter in node.js, including initializing malter, setting up the destination folder, and handling permission issues, with the goal of achieving a functional file upload process.', 'chapters': [{'end': 208.93, 'start': 2.805, 'title': 'Implementing file upload in node.js', 'summary': 'Focuses on implementing file upload for product images using multi-part form data with the malter package in node.js, as an alternative to accepting binary data only.', 'duration': 206.125, 'highlights': ['Implementing file upload functionality for product images using Multi-part form data with the Malter package in Node.js, as an alternative to accepting binary data only.', 'Exploring the use of the Malter package for parsing incoming form data bodies, which cannot be handled by body parser, as it is specifically designed for form data bodies.', 'Discussing the need to accept and store files for product images, and the approach of using Multi-part form data to submit both fields and files, offering a more convenient method for handling the data.']}, {'end': 394.504, 'start': 208.93, 'title': 'Implementing file upload with malter', 'summary': 'Explains the process of implementing file upload functionality using malter in node.js, including initializing malter, setting up the destination folder, and handling permission issues, with the goal of achieving a functional file upload process.', 'duration': 185.574, 'highlights': ['Initializing Malter and setting the destination folder The process of initializing Malter and setting the destination folder for storing incoming files is explained, with a focus on ensuring that the folder is not publicly accessible and may require static folder setup in app.js.', "Handling file upload functionality and middleware usage The usage of Malter's upload object and middleware for handling file uploads, including specifying the field name and using the 'single' method to parse one file, is detailed.", 'Resolving permission issues and restarting the process The identification and resolution of a permission problem related to the destination folder, caused by a leading slash creating an absolute path, is outlined, followed by restarting the process to ensure proper functionality.']}], 'duration': 391.699, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY2805.jpg', 'highlights': ['Implementing file upload functionality for product images using Multi-part form data with the Malter package in Node.js, as an alternative to accepting binary data only.', 'Exploring the use of the Malter package for parsing incoming form data bodies, which cannot be handled by body parser, as it is specifically designed for form data bodies.', 'Discussing the need to accept and store files for product images, and the approach of using Multi-part form data to submit both fields and files, offering a more convenient method for handling the data.', 'Initializing Malter and setting the destination folder for storing incoming files is explained, with a focus on ensuring that the folder is not publicly accessible and may require static folder setup in app.js.', "Handling file upload functionality and middleware usage, including specifying the field name and using the 'single' method to parse one file, is detailed.", 'Resolving permission issues related to the destination folder, caused by a leading slash creating an absolute path, is outlined, followed by restarting the process to ensure proper functionality.']}, {'end': 1087.444, 'segs': [{'end': 505.474, 'src': 'embed', 'start': 473.334, 'weight': 0, 'content': [{'end': 477.797, 'text': 'Now it makes sense because in the headers, I set the content type to application JSON.', 'start': 473.334, 'duration': 4.463}, {'end': 480.859, 'text': "So let's remove that here and let's try sending this again.", 'start': 478.217, 'duration': 2.642}, {'end': 483.782, 'text': 'Now we get message not found.', 'start': 480.879, 'duration': 2.903}, {'end': 488.825, 'text': 'The reason for this is because it should be slash products here, little mistake on my side.', 'start': 484.702, 'duration': 4.123}, {'end': 489.746, 'text': "So let's try again.", 'start': 488.845, 'duration': 0.901}, {'end': 492.768, 'text': 'And now I created a product successfully.', 'start': 489.766, 'duration': 3.002}, {'end': 494.349, 'text': 'So no failure.', 'start': 493.369, 'duration': 0.98}, {'end': 505.474, 'text': 'and we also get an uploads folder with a file in there with some cryptic file name which, if you were to open it in your explorer or finder,', 'start': 495.43, 'duration': 10.044}], 'summary': 'Successfully created a product, no failure, and an uploads folder with a file.', 'duration': 32.14, 'max_score': 473.334, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY473334.jpg'}, {'end': 613.557, 'src': 'embed', 'start': 584.063, 'weight': 1, 'content': [{'end': 589.045, 'text': 'We can be more detailed here and define how we want to store that file.', 'start': 584.063, 'duration': 4.982}, {'end': 592.707, 'text': 'We can also make sure that we only store certain types of files.', 'start': 589.225, 'duration': 3.482}, {'end': 593.968, 'text': "So let's implement both.", 'start': 592.967, 'duration': 1.001}, {'end': 597.209, 'text': 'Let me first implement a storage strategy.', 'start': 594.488, 'duration': 2.721}, {'end': 600.551, 'text': "For that, I'll add a new constant, which I'll name storage.", 'start': 597.269, 'duration': 3.282}, {'end': 607.374, 'text': 'and there i will use the multi package and there the disk storage function.', 'start': 601.371, 'duration': 6.003}, {'end': 613.557, 'text': 'you can pass a javascript object to it to configure it, and this basically allows you to adjust how files get stored.', 'start': 607.374, 'duration': 6.183}], 'summary': 'Implement storage strategy using multi package for file storage.', 'duration': 29.494, 'max_score': 584.063, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY584063.jpg'}, {'end': 745.032, 'src': 'heatmap', 'start': 712.179, 'weight': 0.786, 'content': [{'end': 715.34, 'text': "well, let's see if that works as expected.", 'start': 712.179, 'duration': 3.161}, {'end': 718.74, 'text': 'we now have to pass this to malter here.', 'start': 715.34, 'duration': 3.4}, {'end': 720.901, 'text': 'so now, in this object we pass to malter.', 'start': 718.74, 'duration': 2.161}, {'end': 725.822, 'text': 'we set storage to our storage constant, which holds our own strategy.', 'start': 720.901, 'duration': 4.921}, {'end': 734.884, 'text': "then we save this and then let's send the same request again, maybe with harry potter 6, so that we can see a difference if we do send this.", 'start': 725.822, 'duration': 9.062}, {'end': 738.366, 'text': "let's have a look at the uploads folder.", 'start': 736.124, 'duration': 2.242}, {'end': 745.032, 'text': 'now we see we got the file named with the date and thereafter also with the original file name,', 'start': 738.366, 'duration': 6.666}], 'summary': 'Passing data to malter, setting storage, saving and viewing file uploads.', 'duration': 32.853, 'max_score': 712.179, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY712179.jpg'}, {'end': 810.487, 'src': 'embed', 'start': 758.661, 'weight': 2, 'content': [{'end': 765.243, 'text': 'for one, you can set some limits to, for example, not accept files that are bigger than a certain size.', 'start': 758.661, 'duration': 6.582}, {'end': 769.745, 'text': 'you do this by passing the limits property to that configuration object.', 'start': 765.243, 'duration': 4.502}, {'end': 772.906, 'text': 'you pass to malter and there you can set file size.', 'start': 769.745, 'duration': 3.161}, {'end': 781.635, 'text': 'whoops, that first of all takes another object and then in that object you can set file size to a number in bytes.', 'start': 773.886, 'duration': 7.749}, {'end': 787.161, 'text': 'so you could choose 1024 times 1024.', 'start': 781.635, 'duration': 5.526}, {'end': 794.57, 'text': 'so now you would have one megabyte here, maybe times five, to only accept files up to five megabytes.', 'start': 787.161, 'duration': 7.409}, {'end': 804.365, 'text': 'now that is one additional check you can implement, but maybe you need a more precise filter to accept only certain mime types.', 'start': 795.501, 'duration': 8.864}, {'end': 807.086, 'text': 'for that, you can also set up your own filter.', 'start': 804.365, 'duration': 2.721}, {'end': 810.487, 'text': "so i'll create a new constant which i'll name file filter.", 'start': 807.086, 'duration': 3.401}], 'summary': 'Set file size limits and custom filters for accepting certain mime types in file uploads.', 'duration': 51.826, 'max_score': 758.661, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY758661.jpg'}], 'start': 394.504, 'title': 'Creating and fine-tuning product data', 'summary': 'Covers creating a new product using form data, handling json data parsing, and successful product creation, along with fine-tuning file storage using multer, including storage strategy, file size limits, and custom file filter function implementation, leading to efficient backend file storage and retrieval.', 'chapters': [{'end': 494.349, 'start': 394.504, 'title': 'Creating a new product with form data', 'summary': 'Discusses the process of creating a new product using form data, addressing potential failures in parsing json data and highlighting the successful creation of a product with correct data input and server requests.', 'duration': 99.845, 'highlights': ['The process involves switching to form data for the post request, adding key-value pairs for name and price, and including a file named product image, demonstrating the successful creation of a product with correct data input and server requests.', 'Addressing issues with parsing JSON data, the chapter highlights the failure due to an unexpected token in JSON position zero and the subsequent correction by removing the application JSON content type from the headers.', "The speaker encounters a 'message not found' error, which is resolved by correcting the endpoint to '/products', leading to the successful creation of a product with no failures."]}, {'end': 1087.444, 'start': 495.43, 'title': 'Fine-tuning file storage with multer', 'summary': 'Explains how to fine-tune file storage with multer, including implementing storage strategy, setting file size limits, and creating a custom file filter function, ultimately enabling efficient file storage and retrieval in the backend.', 'duration': 592.014, 'highlights': ["Implementing a storage strategy using the disk storage function from the 'multer' package The chapter details the implementation of a storage strategy using the disk storage function from the 'multer' package, allowing for a more detailed way of storing files and configuring how files get stored.", "Setting file size limits to only accept files up to a certain size The chapter explains the process of setting file size limits to only accept files up to a certain size, demonstrating the use of the 'limits' property and specifying the file size in bytes, thereby implementing an additional check for file size.", 'Creating a custom file filter function to accept only certain mime types The chapter discusses the creation of a custom file filter function to accept only certain mime types, allowing for the filtering out of certain files by accessing file information and using conditions to determine whether to store the file, ultimately enabling precise filtering of file types.']}], 'duration': 692.94, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY394504.jpg', 'highlights': ['Demonstrating successful creation of a product with correct data input and server requests', "Implementing a storage strategy using the disk storage function from the 'multer' package", 'Creating a custom file filter function to accept only certain mime types', "Addressing issues with parsing JSON data and correcting the endpoint to '/products'", 'Setting file size limits to only accept files up to a certain size']}, {'end': 1291.009, 'segs': [{'end': 1121.728, 'src': 'embed', 'start': 1087.444, 'weight': 0, 'content': [{'end': 1091.488, 'text': "we're storing that information now when we retrieve files here.", 'start': 1087.444, 'duration': 4.044}, {'end': 1096.412, 'text': 'for example, when we get all files, we just retrieve the name, the price and the id.', 'start': 1091.488, 'duration': 4.924}, {'end': 1103.478, 'text': 'now we should also add product image here to make sure we get this too, and the same for the route where we get a single product.', 'start': 1096.412, 'duration': 7.066}, {'end': 1106.139, 'text': 'Here we also should retrieve that from the database.', 'start': 1103.718, 'duration': 2.421}, {'end': 1109.941, 'text': "Now we're not done yet though, just adding this here doesn't do the trick.", 'start': 1107, 'duration': 2.941}, {'end': 1113.063, 'text': 'Here for a single product, we do output this here.', 'start': 1110.502, 'duration': 2.561}, {'end': 1121.728, 'text': 'So that is okay, but for all the products, selecting all the fields is one step, but then here we return our own object anyways.', 'start': 1113.744, 'duration': 7.984}], 'summary': 'Retrieve product name, price, and id; add image; ensure database retrieval for single and all products.', 'duration': 34.284, 'max_score': 1087.444, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY1087444.jpg'}, {'end': 1195.134, 'src': 'embed', 'start': 1129.867, 'weight': 1, 'content': [{'end': 1137.689, 'text': 'Now, if we save this and we send another post request to products with our file, the file gets stored.', 'start': 1129.867, 'duration': 7.822}, {'end': 1147.212, 'text': 'If we now get all products, we will see that if we scroll through the list of products here, we get some with a product image,', 'start': 1138.649, 'duration': 8.563}, {'end': 1149.432, 'text': 'because I tested this between cuts a little bit.', 'start': 1147.212, 'duration': 2.22}, {'end': 1162.491, 'text': 'Now, if I pick, for example, the last one here and I copy that product image and I go to the browser and add the path after localhost 3000,', 'start': 1149.852, 'duration': 12.639}, {'end': 1165.233, 'text': "I'm getting an error, a not found error.", 'start': 1162.491, 'duration': 2.742}, {'end': 1167.554, 'text': "So this isn't found, this route isn't found.", 'start': 1165.353, 'duration': 2.201}, {'end': 1170.557, 'text': 'And it makes sense because there is no such route.', 'start': 1167.975, 'duration': 2.582}, {'end': 1181.224, 'text': 'In our project, we got routes for posting and getting our products, but we have no route to handle requests at a slash uploads URL.', 'start': 1171.457, 'duration': 9.767}, {'end': 1184.866, 'text': "And by default, that folder isn't publicly accessible either.", 'start': 1181.684, 'duration': 3.182}, {'end': 1186.508, 'text': "So this all doesn't work.", 'start': 1185.227, 'duration': 1.281}, {'end': 1189.67, 'text': 'Now, there are two possible approaches you can take here.', 'start': 1187.248, 'duration': 2.422}, {'end': 1195.134, 'text': 'You can either implement a route, for example here in the products routing file,', 'start': 1190.39, 'duration': 4.744}], 'summary': 'Testing post request to store file, encountering not found error at slash uploads url.', 'duration': 65.267, 'max_score': 1129.867, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY1129867.jpg'}, {'end': 1244.289, 'src': 'embed', 'start': 1216.529, 'weight': 2, 'content': [{'end': 1218.931, 'text': "the static function here is the one i'm looking for.", 'start': 1216.529, 'duration': 2.402}, {'end': 1222.914, 'text': 'it makes a folder statically so publicly available.', 'start': 1218.931, 'duration': 3.983}, {'end': 1228.738, 'text': 'here i can pass uploads and this will make the uploads folder available to everyone.', 'start': 1222.914, 'duration': 5.824}, {'end': 1235.463, 'text': "if we now save this and therefore the server restarts and i refresh this page, Still doesn't work.", 'start': 1228.738, 'duration': 6.725}, {'end': 1244.289, 'text': 'The reason for this is that if I make it available publicly, I actually have to remove the route, so the folder name, and just access the file name,', 'start': 1236.603, 'duration': 7.686}], 'summary': 'The static function makes a folder publicly available, but may require removing the route for it to work.', 'duration': 27.76, 'max_score': 1216.529, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY1216529.jpg'}], 'start': 1087.444, 'title': 'Updating data retrieval and storage and handling file uploads in express', 'summary': 'Discusses updating the file retrieval process to include product images, ensuring successful post request process and display of product images. it also covers handling file uploads in an express project, addressing route not found error, and making uploads folder publicly available in app.js.', 'chapters': [{'end': 1149.432, 'start': 1087.444, 'title': 'Updating data retrieval and storage', 'summary': 'Discusses updating the file retrieval process to include product images, ensuring that all product fields and images are retrieved and stored in the database, resulting in a seamless post request process and successful display of product images in the product list.', 'duration': 61.988, 'highlights': ['The retrieval process for files is updated to include product images, ensuring that names, prices, IDs, and images are retrieved for all files, resulting in a more comprehensive data retrieval process.', 'The process of storing files is successfully updated, allowing for the seamless post request of products with images, resulting in the successful display of product images in the product list.', 'The chapter also emphasizes the importance of updating the retrieval process for a single product to include product images, ensuring that all necessary data is retrieved from the database for a single product.']}, {'end': 1291.009, 'start': 1149.852, 'title': 'Handling file uploads in express', 'summary': 'Discusses handling file uploads in an express project, addressing the issue of route not found error, implementing a route to handle requests at a slash uploads url, and making the uploads folder publicly available in app.js.', 'duration': 141.157, 'highlights': ['Making the uploads folder publicly available using the static function in app.js This involves adding a new middleware using the static function in app.js to make the uploads folder publicly available, allowing everyone to access it.', 'Implementing a route to handle requests at a slash uploads URL One possible approach suggested is to implement a route in the products routing file to parse all requests coming to slash uploads and manually look up the image file name to return it.', 'Addressing the issue of route not found error when accessing the product image The chapter discusses encountering a not found error when trying to access the product image and explains the reason for the error, which is due to the absence of a route to handle requests at a slash uploads URL.']}], 'duration': 203.565, 'thumbnail': 'https://coursnap.oss-ap-southeast-1.aliyuncs.com/video-capture/srPXMt1Q0nY/pics/srPXMt1Q0nY1087444.jpg', 'highlights': ['The retrieval process for files is updated to include product images, ensuring comprehensive data retrieval.', 'The process of storing files is successfully updated, allowing for seamless post request of products with images.', 'Making the uploads folder publicly available using the static function in app.js.', 'Implementing a route to handle requests at a slash uploads URL.', 'Addressing the issue of route not found error when accessing the product image.']}], 'highlights': ['Creating a custom file filter function to accept only certain mime types', "Implementing a storage strategy using the disk storage function from the 'multer' package", 'The process of storing files is successfully updated, allowing for seamless post request of products with images.', 'The retrieval process for files is updated to include product images, ensuring comprehensive data retrieval.', 'Exploring the use of the Malter package for parsing incoming form data bodies, which cannot be handled by body parser, as it is specifically designed for form data bodies.', "Handling file upload functionality and middleware usage, including specifying the field name and using the 'single' method to parse one file, is detailed.", 'Initializing Malter and setting the destination folder for storing incoming files is explained, with a focus on ensuring that the folder is not publicly accessible and may require static folder setup in app.js.', 'Discussing the need to accept and store files for product images, and the approach of using Multi-part form data to submit both fields and files, offering a more convenient method for handling the data.', 'Demonstrating successful creation of a product with correct data input and server requests', "Addressing issues with parsing JSON data and correcting the endpoint to '/products'", 'Setting file size limits to only accept files up to a certain size', 'Making the uploads folder publicly available using the static function in app.js.', 'Implementing a route to handle requests at a slash uploads URL.', 'Resolving permission issues related to the destination folder, caused by a leading slash creating an absolute path, is outlined, followed by restarting the process to ensure proper functionality.', 'Addressing the issue of route not found error when accessing the product image.']}