Form upload in vibe.d
This tutorial assumes you have a basic knowledge in web development and knows basic programming. I recommend that you first read my previous post titled "Hello world app with the vibe.d web framework" if you are new to vibe.d web framework.
In my previous post on using vibe.d web framework, I showed how vibe.d can make web development easy. In this tutorial, I will show how you can use vibe.d to create a form to submit data and files.
Create a new vibe.d project. I will call mine vibe-upload
;
aberba@mx:~/workspace/d/$ dub init vibe-upload --type=vibe.d
Package recipe format (sdl/json) [json]:
Name [vibe-upload]:
Description [A simple vibe.d server application.]:
Author name [Lawrence Aberba]:
License [proprietary]:
Copyright string [Copyright © 2016, Lawrence Aberba]:
Add dependency (leave empty to skip) []:
Successfully created an empty project in '/home/aberba/workspace/d/'.
Package sucessfully created in vibe-upload
The contents of the project folder is as follows;
aberba@mx:~/workspace/d/vibe-upload$ ls
dub.json public source views
Implementing form for text data
For starters, lets see how sending textual form data (text) works using HTTP
POST. Create an index.dt
file in views
folder and insert the following
diet template code;
doctype html
head
title File upload
body
form(method='post', action='/upload', enctype='multipart/form-data')
p
label(for='title') Title
br
input(name='title',type='text')
p
button(type='submit') Send
The contents of the source/app.d
file will now be as follows;
import vibe.vibe;
void main()
{
auto router = new URLRouter;
router.get("*", staticTemplate!"index.dt");
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, router);
logInfo("Server Running");
runApplication();
}
Unlike the previous vibe.d post, the router.get()
HTTP route here uses the
staticTemplate
function to render index.dt
as a static template for all GET
requests (You can configure it however you want).
Now its time to write a function to handle form submission using a POST request.
Let's write an upload
function above the main
function and register it in
router
to handle form submission through /upload
URL as specified in the
form property (action='/upload'
).
void upload(HTTPServerRequest req, HTTPServerResponse res)
{
import std.stdio;
string title = req.form.get("title");
writeln("Form title is: ", title);
res.redirect("/");
}
The above upload
function will extract the title input data from the
req.form
property using its get
method (use req.query.get()
method for an
HTTP GET request). For now, we just write the title to the console and redirect
to the browser back to the homepage. Run the server and fill-in the text input
of the form which should look like the screenshot below;
Implementing file upload
Now we are ready to add file upload functionality. Open the index.dt
file and
add a file input.
doctype html
head
title File upload
body
form(method='post', action='/upload', enctype='multipart/form-data')
p
label(for='title') Title
br
input(name='title',type='text')
p
p
label(for='document') Select your document file
br
input(name='document', type='file')
p
br
button(type='submit') Send
Create a new folder named uploads
in your public
folder where we will store
all uploaded files. Now lets update the upload
function to support file
upload;
void upload(HTTPServerRequest req, HTTPServerResponse res)
{
import std.stdio;
string title = req.form.get("title");
// File upload here
auto file = "document" in req.files;
try {
moveFile(file.tempPath, Path("./public/uploads") ~ file.filename);
writeln("Uploaded successfully!");
} catch (Exception e) {
writeln("Exception thrown, trying copy");
copyFile(file.tempPath, Path("./public/uploads") ~ file.filename);
}
writeln("Form title is: ", title);
res.redirect("/");
}
In the above code, we use a try/catch block to handle exceptions in cases where
moving file from the temporal folder to public/uploads
fail (file permission
restriction, etc).
NOTE: The maximum default size for file upload is 2MB (2097152 bytes). You can change that in
settings.maxRequestSize = XLU;
whereX
is the number of bytes (1MB is 1048576 bytes). See the documentation of maxRequestSize for more options.
Now it's time to register the upload
function to the /upload
POST route in
router
. Add the following code below
router.get("*", staticTemplate!"index.dt");
to do that;
router.post("/upload", &upload);
Now we are all set test our app. Build the project again and the form should now look like the screenshot below;
Fill-in the title input, select a sample file and submit form. If everything is
successful, you should see the title input value printed in your command-line
and the file should be uploaded to the public/uploads
folder.
I hope you find this tutorial useful. In future tutorial, I will show how you can upload multiple files.