├── home.png ├── .env ├── upload └── images │ ├── images_1629828987916.png │ ├── images_1629828987918.png │ ├── images_1629828987920.png │ ├── image_1_1629828165660.png │ ├── image_2_1629828165661.png │ └── profile_picture_1629827409391.png ├── utils └── appError.js ├── .gitignore ├── config └── database.js ├── package.json ├── api ├── gallery │ ├── gallery.router.js │ ├── gallery.controller.js │ └── gallery.service.js ├── vehicle │ ├── vehicle.router.js │ ├── vehicle.controller.js │ └── vehicle.service.js └── profile │ ├── profile.controller.js │ ├── profile.router.js │ └── profile.service.js ├── app.js ├── LICENSE ├── my_db.sql ├── README.md └── image_upload_example.postman_collection.json /home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/home.png -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | DB_PORT=3306 3 | DB_HOST=localhost 4 | DB_USER=root 5 | DB_PASS= 6 | MYSQL_DB=my_db 7 | JWT_KEY=pwt123 8 | -------------------------------------------------------------------------------- /upload/images/images_1629828987916.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/upload/images/images_1629828987916.png -------------------------------------------------------------------------------- /upload/images/images_1629828987918.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/upload/images/images_1629828987918.png -------------------------------------------------------------------------------- /upload/images/images_1629828987920.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/upload/images/images_1629828987920.png -------------------------------------------------------------------------------- /upload/images/image_1_1629828165660.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/upload/images/image_1_1629828165660.png -------------------------------------------------------------------------------- /upload/images/image_2_1629828165661.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/upload/images/image_2_1629828165661.png -------------------------------------------------------------------------------- /upload/images/profile_picture_1629827409391.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/HEAD/upload/images/profile_picture_1629827409391.png -------------------------------------------------------------------------------- /utils/appError.js: -------------------------------------------------------------------------------- 1 | class AppError extends Error { 2 | constructor(message, statusCode) { 3 | super(message); 4 | this.statusCode = statusCode; 5 | this.isOperational = true; 6 | 7 | Error.captureStackTrace(this, this.constructor); 8 | } 9 | } 10 | 11 | module.exports = AppError; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store* 3 | Icon? 4 | ._* 5 | 6 | # Windows 7 | Thumbs.db 8 | ehthumbs.db 9 | Desktop.ini 10 | 11 | # Linux 12 | .directory 13 | *~ 14 | 15 | 16 | # npm 17 | node_modules 18 | package-lock.json 19 | *.log 20 | *.gz 21 | 22 | 23 | # Coveralls 24 | coverage 25 | 26 | # Benchmarking 27 | benchmarks/graphs -------------------------------------------------------------------------------- /config/database.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql2/promise'); 2 | 3 | const config = { 4 | port: process.env.DB_PORT, 5 | host: process.env.DB_HOST, 6 | user: process.env.DB_USER, 7 | password: process.env.DB_PASS, 8 | database: process.env.MYSQL_DB, 9 | connectionLimit: 50 10 | } 11 | 12 | const pool = mysql.createPool(config); 13 | 14 | module.exports = pool; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon app.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "dotenv": "^10.0.0", 14 | "express": "^4.17.1", 15 | "multer": "^1.4.2", 16 | "mysql2": "^2.2.5" 17 | }, 18 | "devDependencies": { 19 | "nodemon": "^2.0.12" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/gallery/gallery.router.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const { 3 | find, 4 | create 5 | } = require("./gallery.controller"); 6 | const multer = require("multer"); 7 | const path = require("path"); 8 | 9 | const storage = multer.diskStorage({ 10 | destination: './upload/images', 11 | filename: (req, file, cb) => { 12 | return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`) 13 | } 14 | }); 15 | const upload = multer({ 16 | storage: storage, 17 | }).array('images'); 18 | 19 | router.get("/", find); 20 | router.post("/", upload, create); 21 | 22 | 23 | module.exports = router; -------------------------------------------------------------------------------- /api/vehicle/vehicle.router.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const { 3 | find, 4 | create 5 | } = require("./vehicle.controller"); 6 | const multer = require("multer"); 7 | const path = require("path"); 8 | 9 | const storage = multer.diskStorage({ 10 | destination: './upload/images', 11 | filename: (req, file, cb) => { 12 | return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`) 13 | } 14 | }); 15 | const upload = multer({ 16 | storage: storage, 17 | }).fields([{ 18 | name: 'image_1', 19 | maxCount: 1 20 | }, { 21 | name: 'image_2', 22 | maxCount: 1 23 | }]); 24 | 25 | 26 | router.get("/", find); 27 | router.post("/", upload, create); 28 | 29 | 30 | module.exports = router; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const express = require("express"); 3 | const app = express(); 4 | const AppError = require("./utils/appError"); 5 | const profiles = require("./api/profile/profile.router"); 6 | const vehicles = require("./api/vehicle/vehicle.router"); 7 | const gallery = require("./api/gallery/gallery.router"); 8 | 9 | app.use(express.json()); 10 | app.use('/upload', express.static('upload/images')); 11 | app.use("/api/profiles", profiles); 12 | app.use("/api/vehicles", vehicles); 13 | app.use("/api/galleries", gallery); 14 | 15 | app.all('*', (req, res, next) => { 16 | throw new AppError(`Requested URL ${req.path} not found!`, 404); 17 | }); 18 | 19 | const port = process.env.PORT || 4000; 20 | app.listen(port, () => { 21 | console.log("server up and running on PORT :", port); 22 | }); -------------------------------------------------------------------------------- /api/gallery/gallery.controller.js: -------------------------------------------------------------------------------- 1 | const { 2 | find, 3 | create 4 | } = require("./gallery.service"); 5 | 6 | module.exports = { 7 | find: async(req, res) => { 8 | try { 9 | const result = await find(); 10 | return res.status(200).json(result); 11 | } catch (e) { 12 | return res.status(500).json({ 13 | "message": "Internal Server Error" 14 | }); 15 | } 16 | }, 17 | create: async(req, res) => { 18 | try { 19 | var gallery = req.body; 20 | var gallery_image = req.files; 21 | 22 | const result = await create(gallery, gallery_image); 23 | return res.status(201).json(result); 24 | } catch (e) { 25 | return res.status(500).json({ 26 | "message": "Internal Server Error" 27 | }); 28 | } 29 | }, 30 | }; -------------------------------------------------------------------------------- /api/profile/profile.controller.js: -------------------------------------------------------------------------------- 1 | const { 2 | find, 3 | create 4 | } = require("./profile.service"); 5 | 6 | module.exports = { 7 | find: async(req, res) => { 8 | try { 9 | const result = await find(); 10 | return res.status(200).json(result); 11 | } catch (e) { 12 | return res.status(500).json({ 13 | "message": "Internal Server Error" 14 | }); 15 | } 16 | }, 17 | create: async(req, res) => { 18 | try { 19 | var data = req.body; 20 | if (req.file) 21 | data["profile_picture"] = req.file.filename; 22 | 23 | const result = await create(data); 24 | return res.status(201).json(result); 25 | } catch (e) { 26 | return res.status(500).json({ 27 | "message": "Internal Server Error" 28 | }); 29 | } 30 | } 31 | }; -------------------------------------------------------------------------------- /api/profile/profile.router.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const { 3 | find, 4 | create 5 | } = require("./profile.controller"); 6 | const multer = require("multer"); 7 | const path = require("path"); 8 | const AppError = require("./../../utils/appError"); 9 | 10 | const storage = multer.diskStorage({ 11 | destination: './upload/images', 12 | filename: (req, file, cb) => { 13 | return cb(null, `${file.fieldname}_${Date.now()}${path.extname(file.originalname)}`) 14 | } 15 | }); 16 | const upload = multer({ 17 | storage: storage, 18 | fileFilter: function(req, file, cb) { 19 | if (!file.originalname.match(/\.(jpg|JPG|jpeg|JPEG|png|PNG|gif|GIF)$/)) { 20 | req.fileValidationError = 'Only image files are allowed!'; 21 | return cb(new Error('Only image files are allowed!'), false); 22 | } 23 | cb(null, true); 24 | }, 25 | }).single("profile_picture"); 26 | 27 | router.get("/", find); 28 | router.post("/", upload, create); 29 | 30 | 31 | module.exports = router; -------------------------------------------------------------------------------- /api/vehicle/vehicle.controller.js: -------------------------------------------------------------------------------- 1 | const { 2 | find, 3 | create 4 | } = require("./vehicle.service"); 5 | 6 | module.exports = { 7 | find: async(req, res) => { 8 | try { 9 | const result = await find(); 10 | return res.status(200).json(result); 11 | } catch (e) { 12 | return res.status(500).json({ 13 | "message": "Internal Server Error" 14 | }); 15 | } 16 | }, 17 | create: async(req, res) => { 18 | try { 19 | var data = req.body; 20 | if (req.files["image_1"]) 21 | data["image_1"] = req.files["image_1"][0].filename; 22 | 23 | if (req.files["image_2"]) 24 | data["image_2"] = req.files["image_2"][0].filename; 25 | 26 | const result = await create(data); 27 | return res.status(201).json(result); 28 | } catch (e) { 29 | return res.status(500).json({ 30 | "message": "Internal Server Error" 31 | }); 32 | } 33 | }, 34 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Sameera Perera 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /api/vehicle/vehicle.service.js: -------------------------------------------------------------------------------- 1 | const pool = require("../../config/database"); 2 | 3 | module.exports = { 4 | find: async() => { 5 | const connection = await pool.getConnection(); 6 | try { 7 | await connection.beginTransaction(); 8 | const fetchResult = await connection.query( 9 | `SELECT id,name,year,CONCAT('http://192.168.8.140:3000/upload/',image_2) as image_1, 10 | CONCAT('http://192.168.8.140:3000/upload/',image_1) as image_2 11 | FROM vehicle`, 12 | ); 13 | await connection.commit(); 14 | return fetchResult[0]; 15 | } catch (error) { 16 | return error; 17 | } finally { 18 | connection.release(); 19 | } 20 | }, 21 | create: async(data) => { 22 | const connection = await pool.getConnection(); 23 | try { 24 | await connection.beginTransaction(); 25 | const queryResult = await connection.query( 26 | `insert into vehicle 27 | (name,year,image_1,image_2) 28 | values(?,?,?,?)`, [ 29 | data.name, 30 | data.year, 31 | data.image_1, 32 | data.image_2 33 | ] 34 | ); 35 | const fetchResult = await connection.query( 36 | `SELECT id,name,year,CONCAT('http://192.168.8.140:3000/upload/',image_1) as image_1, 37 | CONCAT('http://192.168.8.140:3000/upload/',image_2) as image_2 38 | FROM vehicle WHERE id = ?`, [queryResult[0].insertId] 39 | ); 40 | await connection.commit(); 41 | return fetchResult[0][0]; 42 | } catch (error) { 43 | return error; 44 | } finally { 45 | connection.release(); 46 | } 47 | }, 48 | }; -------------------------------------------------------------------------------- /api/profile/profile.service.js: -------------------------------------------------------------------------------- 1 | const pool = require("../../config/database"); 2 | 3 | module.exports = { 4 | find: async() => { 5 | const connection = await pool.getConnection(); 6 | try { 7 | await connection.beginTransaction(); 8 | const fetchResult = await connection.query( 9 | `SELECT id,first_name,last_name,address,contact_number, 10 | CONCAT('http://192.168.8.140:3000/upload/',profile_picture) AS profile_picture 11 | FROM profile`, 12 | ); 13 | await connection.commit(); 14 | return fetchResult[0]; 15 | } catch (error) { 16 | return error; 17 | } finally { 18 | connection.release(); 19 | } 20 | }, 21 | create: async(data) => { 22 | const connection = await pool.getConnection(); 23 | try { 24 | await connection.beginTransaction(); 25 | const queryResult = await connection.query( 26 | `insert into profile 27 | (first_name,last_name,address,contact_number,profile_picture) 28 | values(?,?,?,?,?)`, [ 29 | data.first_name, 30 | data.last_name, 31 | data.address, 32 | data.contact_number, 33 | data.profile_picture 34 | ] 35 | ); 36 | const fetchResult = await connection.query( 37 | `SELECT id,first_name,last_name,address,contact_number, 38 | CONCAT('http://192.168.8.140:3000/upload/',profile_picture) AS profile_picture 39 | FROM profile WHERE id = ?`, [queryResult[0].insertId] 40 | ); 41 | await connection.commit(); 42 | return fetchResult[0][0]; 43 | } catch (error) { 44 | return error; 45 | } finally { 46 | connection.release(); 47 | } 48 | }, 49 | }; -------------------------------------------------------------------------------- /api/gallery/gallery.service.js: -------------------------------------------------------------------------------- 1 | const pool = require("../../config/database"); 2 | 3 | module.exports = { 4 | find: async() => { 5 | const connection = await pool.getConnection(); 6 | try { 7 | await connection.beginTransaction(); 8 | let result; 9 | const fetchGalleryResult = await connection.query( 10 | `SELECT id,name 11 | FROM gallery` 12 | ); 13 | result = fetchGalleryResult[0]; 14 | for (var i in result) { 15 | const fetchGalleryImageResult = await connection.query( 16 | `SELECT id,CONCAT('http://192.168.8.140:3000/upload/',image) as url 17 | FROM gallery_image WHERE gallery_id = ?`, [result[i].id] 18 | ); 19 | result[i]['images'] = fetchGalleryImageResult[0]; 20 | } 21 | console.log(result); 22 | return result; 23 | } catch (error) { 24 | return error; 25 | } finally { 26 | connection.release(); 27 | } 28 | }, 29 | create: async(gallery, gallery_image) => { 30 | const connection = await pool.getConnection(); 31 | try { 32 | await connection.beginTransaction(); 33 | const queryResult = await connection.query( 34 | `insert into gallery 35 | (name) 36 | values(?)`, [ 37 | gallery.name 38 | ] 39 | ); 40 | const gallery_id = queryResult[0].insertId; 41 | for (var i in gallery_image) { 42 | val = gallery_image[i]; 43 | await connection.query( 44 | `insert into gallery_image 45 | (image,gallery_id) 46 | values(?,?)`, [ 47 | val.filename, 48 | gallery_id 49 | ] 50 | ); 51 | } 52 | let result; 53 | const fetchResult = await connection.query( 54 | `SELECT id,name 55 | FROM gallery WHERE id = ?`, [queryResult[0].insertId] 56 | ); 57 | const images = await connection.query( 58 | `SELECT id,CONCAT('http://192.168.8.140:3000/upload/',image) as url 59 | FROM gallery_image WHERE gallery_id = ?`, [queryResult[0].insertId] 60 | ); 61 | await connection.commit(); 62 | result = fetchResult[0][0]; 63 | result['images'] = images[0]; 64 | return result; 65 | } catch (error) { 66 | return error; 67 | } finally { 68 | connection.release(); 69 | } 70 | }, 71 | }; -------------------------------------------------------------------------------- /my_db.sql: -------------------------------------------------------------------------------- 1 | -- phpMyAdmin SQL Dump 2 | -- version 5.0.4 3 | -- https://www.phpmyadmin.net/ 4 | -- 5 | -- Host: 127.0.0.1 6 | -- Generation Time: Aug 24, 2021 at 07:27 PM 7 | -- Server version: 10.4.17-MariaDB 8 | -- PHP Version: 7.4.15 9 | 10 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 11 | START TRANSACTION; 12 | SET time_zone = "+00:00"; 13 | 14 | 15 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 16 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 17 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 18 | /*!40101 SET NAMES utf8mb4 */; 19 | 20 | -- 21 | -- Database: `my_db` 22 | -- 23 | 24 | -- -------------------------------------------------------- 25 | 26 | -- 27 | -- Table structure for table `gallery` 28 | -- 29 | 30 | CREATE TABLE `gallery` ( 31 | `id` int(11) NOT NULL, 32 | `name` varchar(255) NOT NULL 33 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 34 | 35 | -- -------------------------------------------------------- 36 | 37 | -- 38 | -- Table structure for table `gallery_image` 39 | -- 40 | 41 | CREATE TABLE `gallery_image` ( 42 | `id` int(11) NOT NULL, 43 | `image` varchar(255) NOT NULL, 44 | `gallery_id` int(11) NOT NULL 45 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 46 | 47 | -- -------------------------------------------------------- 48 | 49 | -- 50 | -- Table structure for table `profile` 51 | -- 52 | 53 | CREATE TABLE `profile` ( 54 | `id` int(11) NOT NULL, 55 | `first_name` varchar(255) NOT NULL, 56 | `last_name` varchar(255) NOT NULL, 57 | `address` varchar(255) NOT NULL, 58 | `contact_number` varchar(12) NOT NULL, 59 | `profile_picture` varchar(255) NOT NULL 60 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 61 | 62 | -- -------------------------------------------------------- 63 | 64 | -- 65 | -- Table structure for table `vehicle` 66 | -- 67 | 68 | CREATE TABLE `vehicle` ( 69 | `id` int(11) NOT NULL, 70 | `name` varchar(255) NOT NULL, 71 | `year` varchar(255) NOT NULL, 72 | `image_1` varchar(255) NOT NULL, 73 | `image_2` varchar(255) NOT NULL 74 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 75 | 76 | -- 77 | -- Indexes for dumped tables 78 | -- 79 | 80 | -- 81 | -- Indexes for table `gallery` 82 | -- 83 | ALTER TABLE `gallery` 84 | ADD PRIMARY KEY (`id`); 85 | 86 | -- 87 | -- Indexes for table `gallery_image` 88 | -- 89 | ALTER TABLE `gallery_image` 90 | ADD PRIMARY KEY (`id`), 91 | ADD KEY `gallery_id` (`gallery_id`); 92 | 93 | -- 94 | -- Indexes for table `profile` 95 | -- 96 | ALTER TABLE `profile` 97 | ADD PRIMARY KEY (`id`); 98 | 99 | -- 100 | -- Indexes for table `vehicle` 101 | -- 102 | ALTER TABLE `vehicle` 103 | ADD PRIMARY KEY (`id`); 104 | 105 | -- 106 | -- AUTO_INCREMENT for dumped tables 107 | -- 108 | 109 | -- 110 | -- AUTO_INCREMENT for table `gallery` 111 | -- 112 | ALTER TABLE `gallery` 113 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 114 | 115 | -- 116 | -- AUTO_INCREMENT for table `gallery_image` 117 | -- 118 | ALTER TABLE `gallery_image` 119 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 120 | 121 | -- 122 | -- AUTO_INCREMENT for table `profile` 123 | -- 124 | ALTER TABLE `profile` 125 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 126 | 127 | -- 128 | -- AUTO_INCREMENT for table `vehicle` 129 | -- 130 | ALTER TABLE `vehicle` 131 | MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; 132 | 133 | -- 134 | -- Constraints for dumped tables 135 | -- 136 | 137 | -- 138 | -- Constraints for table `gallery_image` 139 | -- 140 | ALTER TABLE `gallery_image` 141 | ADD CONSTRAINT `gallery_image_ibfk_1` FOREIGN KEY (`gallery_id`) REFERENCES `gallery` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; 142 | COMMIT; 143 | 144 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 145 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 146 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Contributors][contributors-shield]][contributors-url] 2 | [![Forks][forks-shield]][forks-url] 3 | [![Stargazers][stars-shield]][stars-url] 4 | [![Issues][issues-shield]][issues-url] 5 | [![LinkedIn][linkedin-shield]][linkedin-url] 6 | 7 |

8 |

9 | Express-Js-REST-API-Image-Uploade-Complete-Example 10 | Node Express JS REST API Image Upload With MySQL Complete Example || Single/Multiple/Dynamic Upload

11 |

12 | 13 | [![Product Name Screen Shot][product-screenshot]](https://example.com) 14 | 15 | This tutorial will cover all you need to know about Node express js REST API image uploaded with MySQL. 16 | This complete example will cover single image upload with data, multiple images upload with data and, dynamic numbers of images upload with data. 17 | below I mention source code, MySQL backup, and API documentation. 18 | 19 | ### Built With 20 | In this example, I used MySQL2 package for async transactions. if u don't need async transactions feel free to use MySQL package. 21 | 22 | * [MySQL2](https://www.npmjs.com/package/mysql2) 23 | * [Multer](https://www.npmjs.com/package/multer) 24 | 25 | 26 | 27 | ## Getting Started 28 | 29 | This is an example of how you may give instructions on setting up your project locally. 30 | To get a local copy up and running follow these simple example steps. 31 | 32 | ### Prerequisites 33 | 34 | This is an example of how to list things you need to use the software and how to install them. 35 | * npm 36 | ```sh 37 | npm install npm@latest -g 38 | ``` 39 | * MySQL 40 | 41 | ### Installation 42 | 43 | 1. Clone the repo 44 | ```sh 45 | git clone https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example.git 46 | ``` 47 | 2. Install NPM packages 48 | ```sh 49 | npm install 50 | ``` 51 | 3. Make sure database details are correct `.env` 52 | ```sh 53 | PORT=3000 54 | DB_PORT=3306 55 | DB_HOST=localhost 56 | DB_USER=root 57 | DB_PASS= 58 | MYSQL_DB=my_db 59 | JWT_KEY=pwt123 60 | 61 | 62 | 63 | ## Usage 64 | 65 | Demo video - https://youtu.be/t6hiHIqSnQg 66 | 67 | _For more examples, please refer to the [Documentation](https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/blob/main/image_upload_example.postman_collection.json)_. upload this json file to postman. 68 | 69 | 70 | 71 | 72 | ## License 73 | 74 | Distributed under the MIT License. See `LICENSE` for more information. 75 | 76 | 77 | 78 | ## Contact 79 | 80 | You Tube - [@programming_night](https://www.youtube.com/channel/UCKn8mSyZt_qwXK1Kzr6hA9w) - Programming Night 81 | 82 | Project Link: [https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example](https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example) 83 | 84 | 85 | 86 | [contributors-shield]: https://img.shields.io/github/contributors/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example.svg?style=for-the-badge 87 | [contributors-url]: https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/graphs/contributors 88 | [forks-shield]: https://img.shields.io/github/forks/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example.svg?style=for-the-badge 89 | [forks-url]: https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/network/members 90 | [stars-shield]: https://img.shields.io/github/stars/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example.svg?style=for-the-badge 91 | [stars-url]: https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/stargazers 92 | [issues-shield]: https://img.shields.io/github/issues/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example.svg?style=for-the-badge 93 | [issues-url]: https://github.com/Sameera-Perera/Express-Js-REST-API-Image-Uploade-Complete-Example/issues 94 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 95 | [linkedin-url]: http://www.linkedin.com/in/sameera-perera-1148081b8 96 | [product-screenshot]: home.png 97 | -------------------------------------------------------------------------------- /image_upload_example.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "eb14c125-6473-4b1a-97db-b296ee7e605d", 4 | "name": "image_upload_example", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "profile", 10 | "request": { 11 | "method": "GET", 12 | "header": [], 13 | "url": { 14 | "raw": "http://localhost:3000/api/profiles", 15 | "protocol": "http", 16 | "host": [ 17 | "localhost" 18 | ], 19 | "port": "3000", 20 | "path": [ 21 | "api", 22 | "profiles" 23 | ] 24 | } 25 | }, 26 | "response": [] 27 | }, 28 | { 29 | "name": "profile", 30 | "request": { 31 | "method": "POST", 32 | "header": [], 33 | "body": { 34 | "mode": "formdata", 35 | "formdata": [ 36 | { 37 | "key": "first_name", 38 | "value": "Vicki", 39 | "type": "text" 40 | }, 41 | { 42 | "key": "last_name", 43 | "value": "Hanson", 44 | "type": "text" 45 | }, 46 | { 47 | "key": "address", 48 | "value": "waterford", 49 | "type": "text" 50 | }, 51 | { 52 | "key": "contact_number", 53 | "value": "(431)-765-6773", 54 | "type": "text" 55 | }, 56 | { 57 | "key": "profile_picture", 58 | "type": "file", 59 | "src": "/C:/Users/masrk/Downloads/undraw_image_options_7uph (2).png" 60 | } 61 | ] 62 | }, 63 | "url": { 64 | "raw": "http://localhost:3000/api/profiles", 65 | "protocol": "http", 66 | "host": [ 67 | "localhost" 68 | ], 69 | "port": "3000", 70 | "path": [ 71 | "api", 72 | "profiles" 73 | ] 74 | } 75 | }, 76 | "response": [] 77 | }, 78 | { 79 | "name": "vehicle", 80 | "request": { 81 | "method": "GET", 82 | "header": [], 83 | "url": { 84 | "raw": "http://localhost:3000/api/vehicles", 85 | "protocol": "http", 86 | "host": [ 87 | "localhost" 88 | ], 89 | "port": "3000", 90 | "path": [ 91 | "api", 92 | "vehicles" 93 | ] 94 | } 95 | }, 96 | "response": [] 97 | }, 98 | { 99 | "name": "vehicle", 100 | "request": { 101 | "method": "POST", 102 | "header": [], 103 | "body": { 104 | "mode": "formdata", 105 | "formdata": [ 106 | { 107 | "key": "name", 108 | "value": "BMW", 109 | "type": "text" 110 | }, 111 | { 112 | "key": "year", 113 | "value": "2012", 114 | "type": "text" 115 | }, 116 | { 117 | "key": "image_1", 118 | "type": "file", 119 | "src": "/C:/Users/masrk/Downloads/undraw_Posting_photo_re_plk8 (1).png" 120 | }, 121 | { 122 | "key": "image_2", 123 | "type": "file", 124 | "src": "/C:/Users/masrk/Downloads/undraw_insert_08ir (1).png" 125 | } 126 | ] 127 | }, 128 | "url": { 129 | "raw": "http://localhost:3000/api/vehicles", 130 | "protocol": "http", 131 | "host": [ 132 | "localhost" 133 | ], 134 | "port": "3000", 135 | "path": [ 136 | "api", 137 | "vehicles" 138 | ] 139 | } 140 | }, 141 | "response": [] 142 | }, 143 | { 144 | "name": "gallery", 145 | "request": { 146 | "method": "GET", 147 | "header": [], 148 | "url": { 149 | "raw": "http://localhost:3000/api/galleries", 150 | "protocol": "http", 151 | "host": [ 152 | "localhost" 153 | ], 154 | "port": "3000", 155 | "path": [ 156 | "api", 157 | "galleries" 158 | ] 159 | } 160 | }, 161 | "response": [] 162 | }, 163 | { 164 | "name": "gallery", 165 | "request": { 166 | "method": "POST", 167 | "header": [ 168 | { 169 | "key": "name", 170 | "value": "my_images", 171 | "type": "text", 172 | "disabled": true 173 | }, 174 | { 175 | "key": "images", 176 | "value": "", 177 | "type": "text", 178 | "disabled": true 179 | } 180 | ], 181 | "body": { 182 | "mode": "formdata", 183 | "formdata": [ 184 | { 185 | "key": "name", 186 | "value": "my_images", 187 | "type": "text" 188 | }, 189 | { 190 | "key": "images", 191 | "type": "file", 192 | "src": [ 193 | "/C:/Users/masrk/Downloads/undraw_insert_08ir.png", 194 | "/C:/Users/masrk/Downloads/undraw_image_options_7uph.png", 195 | "/C:/Users/masrk/Downloads/undraw_image_options_7uph (1).png" 196 | ] 197 | } 198 | ] 199 | }, 200 | "url": { 201 | "raw": "http://localhost:3000/api/galleries", 202 | "protocol": "http", 203 | "host": [ 204 | "localhost" 205 | ], 206 | "port": "3000", 207 | "path": [ 208 | "api", 209 | "galleries" 210 | ] 211 | } 212 | }, 213 | "response": [] 214 | } 215 | ] 216 | } --------------------------------------------------------------------------------