Send Files With HTML5's Form and Catching with Express.js Handlebars Templating
Hi this is a new post about Express.js and Handlebars, I want to cover a little about send files with default form way and fetch, thus reach the goal of send data and files with JS.
Structure of the directory
First of all, you need to create a directory whatever name you want to choose, I choose filesjs just to be easy.
Initiate Package JSON
Second, run this command to create our Package JSON and in this way start installing packages.
$ npm init -y
Install Expres.js and Express Handlebars
To install dependencies you need to run this command, i is for install and the dependencies are next
$ npm i express express-handlebars
Handlebars Structure
After that we need to create views directory, layouts directory and create our server.js file, if you do the same as I did you can have something like this:
Third we need to add home, 404, 500, sendFiles views to our project and the main layout or default layout.
<div class="container"><div class="row"><div class="col-5"><h2>Sending files </h2><form action="/api/sendfiles/{{ year }}/{{ month }}" method="POST" enctype="multipart/form-data"><div class="form-group"><label for="userName">User Name</label><input type="text" id="userName" name="userName" class="form-control" value="Flame Princess"></div><div class="form-group"><label for="userEmail">User Email</label><input type="email" id="userEmail" name="userEmail" class="form-control" value="flame_princess@adventuretime.org"></div><div class="form-group"><label for="userFile">Insert Just Images</label><input type="file" id="userFile" name="userFile" accept="image/*" ></div><button type="submit" class="btn btn-primary">Send Data</button></form></div></div></div>
If you see the examples above in the main layout, I added Bootstrap CDN to add a little style to the form view and in the sendFiles view I added all the inputs and labels of the common form behaves, pay attention that I added {{year}} and {{month}} to the URL because we will add some dynamic variables, and also I added the method and the enctype in this case is “multipart/form-data” to send files
Our Server
Well this is the great part I am trying to be concise and neat, first I have the express framework then the app and the express handlebars library, importing home, sendFiles, API and thankyou these are functions that receive two parameter request and response, but I divided in one JS file called handles.js in our lib directory to be clean and for JEST testings then I added the engine and setting to the view engine templating, second I added the views, third the post view in this case I added the library multiparty a good library to manage multipart/form-data (files) and you also need to install it:
$ npm i multiparty
The interesting part of the multiparty is that it parses all the information from the request and pass it in two parts the fields and the files (a perfect way to manage data), but we need to instantiate a new Form and use the parse method adding req, error, fields and files, finally I added the error’s Class if something happens and passing the req, res, fields and files to the sendFilesCommon function
Four, I finished with the 404, 500 and the listen method to start our server.
Handles.js file part, in this part is just the request and response for home, sendfiles, thank-you. The API have two functions to manage the files and fields from the request, but if you see closely you can see that the function needs req, res, fields and files that we shared before on the post method
exports.home = ( req, res ) => res.render( 'home' )
exports.sendFiles = ( req, res ) => res.render( 'sendfiles', {
year: '2022',
month: 'july'} )
exports.thankyou = ( req, res ) => res.render( 'thank-you' )
exports.api = {
sendFilesCommon: ( req, res, fields, files ) => {
console.log( 'Fields: ', fields )
console.log( 'Files ', files )
res.redirect( 303, '/thank-you')
},
sendFilesFetch: ( req, res, fields, files ) => {
console.log( 'fiels: ', fields )
console.log( 'files', files )
res.json({
success: true
})}}
Run Server
If we click on the send data button, we can see that it sends us to the thank-you page
If we check the console output, we can see all the data from the user
Fetch Part
We need to change a little our server and view, adding script part and just we need to specify the method and the body in this case the browser does all the work for us check that I didn’t specify the headers (multipart/form-data) and also I used the new FormData() Object and with this all is done!
In addition, a fetch API and adding the h2 to tell the client if the process is successfully or if we have an error :(
<div class="container">
<div class="row">
<div class="col-5">
<h2>Sending files </h2>
<form id="formFiles">
<div class="form-group">
<label for="userName">User Name</label>
<input type="text" id="userName" name="userName" class="form-control" value="Flame Princess">
</div>
<div class="form-group">
<label for="userEmail">User Email</label>
<input type="email" id="userEmail" name="userEmail" class="form-control" value="flame_princess@adventuretime.org">
</div>
<div class="form-group">
<label for="userFile">Insert Just Images</label>
<input type="file" id="userFile" name="userFile" accept="image/*" >
</div>
<button type="submit" class="btn btn-primary">Send Data</button></form>
<h2 id="fetch_data"></h2></div></div></div><script>
let form = document.querySelector( '#formFiles' ),
h2 = document.querySelector( '#fetch_data' )
form.addEventListener( 'submit', e => {
e.preventDefault()
fetch( '/api/sendfilesfetch/{{year}}/{{month}}', {
method: 'POST',
body: new FormData( form )
})
.then( raw => {
if( raw.status < 200 || raw.status >= 300 ){
console.log( `Error managing your data ${ new Error( raw.status ) }`
)}
return raw.json()
})
.then( data => {
console.log( data )
h2.textContent = 'Your data was uploaded'
})
.catch( err => {
console.log( new Error( err.message ) )
h2.textContent = 'there was a problem uploading your data :('
})
})
</script>
Run server again
Send files!
Cool! we send the files, and we receive a success true everything is cool, but we need to check the console again
COOL!!! We did it
Complete code of our server
const express = require( 'express' ),
app = express(),port = process.env.PORT || 1024,{ engine } = require( 'express-handlebars' ),
{home, sendFiles, api, thankyou} = require( './lib/handles' ),
multiparty = require( 'multiparty' )
app.use( express.urlencoded({ extended: false }))
app.engine( 'handlebars', engine({defaultLayout: 'main'}))
app.set( 'view engine', 'handlebars' )
app.get( '', home )app.get( '/sendfiles', sendFiles )
app.get( '/thank-you', thankyou )
app.post( '/api/sendfiles/:year/:month', ( req, res ) => {const form = new multiparty.Form()form.parse( req, ( err, field, files ) => {if( err ) new Error( `Error Handling The POST ${ err.message }` )api.sendFilesCommon( req, res, field, files )})})
app.post( '/api/sendfilesfetch/:year/:month', ( req, res ) => {const form = new multiparty.Form()form.parse( req, ( err, field, files ) => {if( err ) new Error( `Error Handling The POST ${ err.message }` )api.sendFilesFetch( req, res, field, files )})})
app.use( ( req, res ) => res.status( 404 ).render( '404' ))
app.use( ( err, req, res, next ) => res.status( 500 ).render( '500' ))
app.listen( port, console.log( `http:127.0.0.1:${ port }` ))
Conclusion
In conclusion, sending data is really common these days and also sending files are really handy we are all exchanging data for instance uploading in our Drive or sending images on social media we are always uploading files that is why this small example can help you with your next Express.js and Handlebars project.