Create Memes Generator with NodeJS
By Prgmaz 06 May 2021

Thumbnail

Hello Guys, It’s been a while since I wrote my last blog, So let’s just dive into it.

What we need for this tutorial.

  1. HTML and CSS
  2. Some Javascript
  3. Nodejs and Express
  4. Axios

Let’s create a folder named meme_generator and initialize node project by typing npm init -y NPM INITIALIZE

Now we have our NodeJS project initialized, Let’s open code in that folder and setup our express and webservers config.

I’m going to create a index.js, public and views directory.

  • Public directory will store our /assets files like js, css, images etc.
  • Views directory will store our views(webpages).
  • Index.js will contain code for our server.

Project Structure

First let’s setup our express server. Let’s install some modules in that folder by typing npm install express ejs axios lodash.

  • Express will create our server.
  • ejs is a templating module.
  • axios is a http request library which will make requests to imgflip api.
  • lodash is some functions for list that we’re gonna need.

INSTALLING MODULES

Now that we installed our modules, Let’s open our index.js and write some code.

// IMPORTS
const express = require('express');
const axios = require('axios').default;
const _ = require('lodash');

// CONSTANTS
const app = express();

// MIDDLEWARES
app.use(express.json()); // This will parse json payload.
app.use(express.urlencoded({extended: true}); // This will parse urlencoded payload.
app.use(express./assets('public')); // This will serve public directory on our server.
app.set('view engine', 'ejs'); // So express uses ejs as its templating engine.

// Routes


// Listeing to server
app.listen(3000, () => {
  console.log("Server is running on http://localhost:3000");
});

Now we have our code and Server code ready. To run it we’re gonna need Nodemon(a library which reruns file when code is changed). Let’s install this globally. npm install -g nodemon

Now let’s run this index.js. Type nodemon index.js in your terminal.

If you open browser and go to http://localhost:3000. A message will show up.

BROWSER ROUTE

cannot get '/'

It means our server is running correctly. Now let’s setup some routes.

In this I’m gonna create two routes.

  • ’/’ will contain our meme generator.
  • ‘/generate’ will have method POST and send request to imgflip API and returns response.
// IMPORTS
const express = require('express');
const axios = require('axios').default;
const _ = require('lodash');

// CONSTANTS
const app = express();

// MIDDLEWARES
app.use(express.json()); // This will parse json payload.
app.use(express.urlencoded({extended: true}); // This will parse urlencoded payload.
app.use(express./assets('public')); // This will serve public directory on our server.
app.set('view engine', 'ejs'); // So express uses ejs as its templating engine.

// Routes
app.get('/', (req, res) => {
  return res.render("index");
});

app.post("/generate", (req, res) => {
  return res.send("Hello World!");
});

// Listeing to server
app.listen(3000, () => {
  console.log("Server is running on http://localhost:3000");
});

Now our code is setup let’s dive into our frontend. Create a file named index.ejs in your views directory.

Write some code to make post request to /generate route with params of template_id, username, password, text0, text1 with form-urlencoded encoding type. Like in below code block.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Input</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <div class="d-flex">
        </div>
        <form action="/generate" method="POST" enctype="application/x-www-form-urlencoded">
            <div class="input-container">
                <label for="">ID</label>
                <input id="template_id" required name="template_id" type="text">
            </div>
            <div class="input-container">
                <label for="">Username</label>
                <input required name="username" type="text">
            </div>
            <div class="input-container">
                <label for="">Password</label>
                <input required name="password" type="password">
            </div>
            <div class="input-container">
                <label for="">Upper text</label>
                <input required name="text0" type="text">
            </div>
            <div class="input-container">
                <label for="">Lower Text</label>
                <input required name="text1" type="text">
            </div>
            <button type="submit" class="btn-primary">
                Send
            </button>
        </form>
    </div>
</body>

</html>

Let’s style this now, Create style.css in your public directory.

.container{
    display: flex;
    flex-direction: column;
}

.input-container{
    margin: 15px;
    display: flex;
    flex-direction: column;
    width: 30%;
}

.input-container label{
    font-size: 24px;
    font-family: 'Consolas', sans-serif;
    font-weight: bold;
}

.input-container input{
    border-radius: 25px;
    padding: 10px;
    border: 1px solid grey;
}

.btn-primary{
    width: 30%;
    height: 50px;
    border: 1px solid white;
    border-radius: 15px;
    margin: 15px;
    background-color: rgb(4, 156, 194);
    color: white;
    cursor: pointer;
}

.d-flex{
    display: flex;
}

.d-flex img{
    width: auto;
    height: 100px;
    margin: 10px;
    border: 1px solid black;
    cursor: pointer;
}

If you go to / route in your browser you will see this .

BROWSER ROUTE

Now let’s setup our POST route. In index.js file. Make an request to imgflip api and pass the params that we have got when we send request from our index page of our server.

app.post("/generate", (req, res) => {
	axios
		.post(
			"https://api.imgflip.com/caption_image",
			{},
			{
				params: {
					template_id: req.body.template_id,
					username: req.body.username,
					password: req.body.password,
					text0: req.body.text0,
					text1: req.body.text1,
				},
			}
		)
		.then((response) => {
			return res.send(`<img src=${response.data.data.url}>`);
		}).catch((e) => {
            return res.status(403).send("403 Client Error")
        });
});

NOTE: You will need username and password for making a request to imgflip api, Create your account on imgflip

Now that we have our POST route fully complete, Let’s create our frontend.

Let’s get all memes template from imgflip api and display 10 random meme_template which our user can select. Go to your / route and write this code.

app.get("/", (req, res) => {
	axios
		.get("https://api.imgflip.com/get_memes")
		.then((memes) => {
			return res.render("index", {
				memes: _.sampleSize(memes.data.data.memes, 10)
			});
		})
		.catch((e) => {
			return res.status(500).send("500 Internal Server Error");
		});
});
  • sampleSize method takes list as argument and number of size and gives number of random memes.
  • if there is error this will generate internet server error message.

Now let’s iterate and display image in our index view.

<div class="container">
    <div class="d-flex">
        <% for(const i of memes){ %>
            <img class="meme_image" id=<%= i.id %> src=<%= i.url %>>
        <% } %>
    </div>
    <form action="/generate" method="POST" enctype="application/x-www-form-urlencoded">
    ...
</div>

Now we want to add event listener to all image so that when we click on image, it’s id will change on click.

...
</body>

<script>
    var images = document.getElementsByClassName("meme_image");
    var templateInput = document.getElementById("template_id");
    for(const i of images){
        i.addEventListener('click', (e) => {
            templateInput.value = i.id;
        });
    }
</script>
</html>

Now our project is complete. If you click on a image and type in your username and password and text and click Submit your meme will be generated. BROWSER ROUTE BROWSER ROUTE

You can download this source code from my Github.

Visit this Project on Github

Naman Baranwal
Hi, I’m Prgmaz. I’m a Web, Game and App Developer.

Tags