June 28, 2024

ExpressJS: Pug Template Iteration Examples

In the post ExpressJS: Pug Template Engine Integration With Examples we have seen how you can use Pug template with Express.js app. In this post we'll see how to iterate over an array or object in Pug template.

Iteration in Pug

In Pug you can iterate over values using one of the following-

  1. each
  2. while

For example, using each with an array of values.

ul
  each val in [1, 2, 3, 4, 5]
    li= val

This transforms to an HTML

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

Using each to iterate over an object and accessing both key and value.

ul
  each val, key in {name:'Badal', age: 34, gender:'M'}
    li= key + ': ' + val

This transforms to an HTML

<ul>
  <li>name: Badal</li>
  <li>age: 34</li>
  <li>gender: M</li>
</ul>

Using while to create a loop

- var n = 0;
ul
  while n < 5
    li= n++

This transforms to an HTML

<ul>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

Express.js - Pug iteration example

Let's assume we have an array of User objects which we want to iterate and display in our view named 'test' which is created as a Pug template.

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

const users = [{name:'Reene', age: 28, gender:'F'}, 
    {name:'Badal', age: 34, gender:'M'},
    {name:'Vidyut', age: 25, gender:'M'},
    {name:'Dhriti', age: 29, gender:'F'}
]
app.get('/', (req, res) => {
    res.render('test', {users: users, pageTitle: 'User Page'});
})
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

public\css\main.css

CSS used for styling.

.main{
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

.header{
  width: 100%;
  height: 3rem;
  text-align: center;
  background-color: #6d70a8;
  padding: 1 2rem;
  color: antiquewhite;
}

views\test.pug

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
    link(rel="stylesheet", href="/css/main.css")
  body 
    h2.header A pug template
    table
      each user in users
        tr 
          td= user.name
          td= user.age
          td #{user.gender}

As you can see iteration is done using each, in each iteration one user object is taken from the users array and the properties are displayed. A table is created where each row represents one user record.

This is the generated HTML that you can view by going to page source.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>User Page</title>
    <link rel="stylesheet" href="/css/main.css">
  </head>
  <body> 
    <h2 class="header">A pug template</h2>
    <table>
        <tr> 
          <td>Reene</td>
          <td>28</td>
          <td>F</td>
        </tr>
        <tr> 
          <td>Badal</td>
          <td>34</td>
          <td>M</td>
        </tr>
        <tr> 
          <td>Vidyut</td>
          <td>25</td>
          <td>M</td>
        </tr>
        <tr> 
          <td>Dhriti</td>
          <td>29</td>
          <td>F</td>
        </tr>
    </table>
  </body>
</html>

Getting the index

You can also get the index as you iterate. Here is the same Pug template as used above with the inclusion of index to get serial number.

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
    link(rel="stylesheet", href="/css/main.css")
  body 
    h2.header A pug template
    table
      each user, index in users
        tr
          td= index+1+'.'
          td= user.name
          td= user.age
          td #{user.gender}

If you run app.js and then access http://localhost:3000/

Pug template iteration ExpressJS

Pug object iteration ExpreeeJS example

If you want to iterate an object and extract the (key, value) pairs.

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
//Object to be iterated
const user = {name:'Reene', age: 28, gender:'F'};
app.get('/', (req, res) => {
    res.render('test', {user: user, pageTitle: 'User Page'});
})
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

views\test.pug

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
    link(rel="stylesheet", href="/css/main.css")
  body 
    h2.header A pug template
    ul
      each val, key in user
        li= key.charAt(0).toUpperCase() + key.substr(1).toLowerCase() + ': ' + val

CSS remains the same as used in the above example.

With that you'll get the result as-

  Name: Reene
  Age: 28
  Gender: F

That's all for the topic ExpressJS: Pug Template Iteration Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

ExpressJS: Pug Template Engine Integration With Examples

The previous post ExpressJS Template Engines Introduction gives an introduction to template engines that can be used with Express.js. In this article we'll see how to use Pug template engine and its integration with Express.js.

Installing Pug

You can install Pug by using the following command.

npm install pug

Settings in Express.js for using Pug

You need to configure Pug as the view engine in Express.js app.

app.set('views', './views')

This setting sets the views directory in the application root directory as the location where template files are saved. Template engine will search this directory to locate the template that has to be transformed.

app.set('view engine', 'pug')

This setting sets pug as the template engine.

Writing Pug template

If you have used express-generator to create project structure you should already be having a views folder or you can create a views folder with in the app root directory and with in the view folder create a new file that has the extension .pug.

Pug templates don't use the full HTML tags, you just need to give the element name followed by the content. Ensure proper indentation for nested elements.

views\home.pug

doctype html
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title #{pageTitle}
    link(rel="stylesheet", href="/css/main.css")
  body
    div#view.main
      h2.header #{heading.toUpperCase()}
      p= message

Some important points to note here-

  • To define an ID you can use #idname syntax.
    	div#view
    	
  • CSS classes may be defined using a .classname syntax
    div#view.main
    h3.header
    
    With the div main is the class that is used. With h3 element header class is used.
  • There are 3 placeholders in the template pageTitle, heading and message. You can either use #{} for a variable or equal sign (=) for getting the values for these variables.
    The code in between #{ and } is evaluated, escaped, and the result buffered into the output of the template being rendered. You can use JavaScript expression which can be evaluated.
    h2.header #{heading.toUpperCase()}
    

public\css\main.css

CSS used for styling.

.main{
  padding: 0;
  margin: 0;
  font-family: sans-serif;
}

.header{
  width: 100%;
  height: 3rem;
  text-align: center;
  background-color: #6d70a8;
  padding: 1 2rem;
  color: antiquewhite;
}

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

// To serve static files like CSS
app.use(express.static(path.join(__dirname, 'public')));

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.get('/', (req, res) => {
    res.render('home', {pageTitle: 'MyPage', heading: 'Pug Template Example',
    message: 'Hello From Pug Template Engine'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

Some important points to note here-

  • Properties are set for template engine using app.set() method.
  • In res.render() method template name is passed as the first parameter and as a second parameter values are set for the variables in the template.
  • Using the built-in middleware express.static() path to public directory is set where static files are stored. That is why, in the Pug template, you could link to stylesheet by giving the path relative to public.
    link(rel="stylesheet", href="/css/main.css")
    

This is the generated HTML that you can view by going to page source.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyPage</title>
    <link rel="stylesheet" href="/css/main.css">
  </head>
  <body>
    <div class="main" id="view">
      <h2 class="header">PUG TEMPLATE EXAMPLE</h2>
      <p>Hello From Pug Template Engine</p>
    </div>
  </body>
</html>

That's all for the topic ExpressJS: Pug Template Engines Integration With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 26, 2024

ExpressJS Template Engines Introduction

For creating view part of Express.js web app you can use HTML but that doesn't give you that much flexibility to create dynamic content. In order to make your HTML dynamic you can use template engines like Pug, EJS, Mustache. These template engines take the template as input and transform it into an HTML file at runtime by replacing variables in a template file with actual values.

ExpressJS Template Engines

Settings in Express.js for rendering templates

In the app.js or index.js which are the conventional names for the entry point of your Express app you need to set the following application setting properties for the template engine you are using.

1. You need to set the location of the directory where the template files are saved. For that 'views' property is used.

app.set('views', './views')

Above setting sets the views directory in the application root directory as the location where template files are saved. Template engine will search this directory to locate the template that has to be transformed.

2. As already mentioned, there are many template engines available so you need to install the one you are going to use and also set it in your Express app by using the property named 'view engine'.

app.set('view engine', 'pug')

Above setting sets pug as the template engine.

How to render template in Express.js

Steps for using template engine and getting the end HTML file which is sent to the client are as given below.

  1. Install the template engine you want to use.
    For example, if you are going to use pug as template engine.
    npm install pug -save
    
  2. Set the properties as mentioned above to configure the template engine in the Express app.
  3. For transforming and sending the resultant HTML to the client you can use res.render() method.
    res.render(view, locals, callback)
    
    • view- File path of the template to render.
    • locals- An object whose properties define values for local variables to be replaced in the view template. This is an optional parameter.
    • callback- A callback function. Function takes two parameters (err, html) where err encapsulates the error, if any and html stores the rendered HTML as string. This is an optional parameter.

Pug Template Example

Here is a simple example to show how to use pug template engine.

views/home.pug

doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title #{pageTitle}
    body 
        h3(align='center') A pug template
        p= message

There are 2 variables in the template pageTitle and message. You can either use #{} for a variable or equal sign (=).

app.js

const express = require('express');

const app = express();

const port = 3000;
const path = require('path');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.get('/', (req, res) => {
    res.render('home', {pageTitle: 'MyPage', 
    message: 'Hello From Pug Template Engine'});
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

You can see the properties that are set for template engine. In res.render() method template name is passed as the first parameter and as a second parameter values are set for the variables in the template.

Once you run the app and access URL- http://localhost:3000/

Pug with Express.js

If you view the page source you can see the rendered HTML.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyPage</title>
  </head>
  <body> 
    <h3 align="center">A pug template</h3>
    <p>Hello From Pug Template Engine</p>
  </body>
</html>

That's all for the topic ExpressJS Template Engines Introduction. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 25, 2024

Java Stream Collectors.joining() Method With Examples

In this tutorial we’ll see how to use Collectors.joining() method to concatenate the input elements into a String. It is a handy utility method provided by the Collectors class in Java Stream API to quickly convert array elements or elements in a collection to String.

There are three overloaded Collectors.joining() method-

  • Collector<CharSequence,?,String> joining()- Concatenates the input elements into a String, in encounter order.
  • Collector<CharSequence,?,String> joining(CharSequence delimiter)- In this method you can also pass a delimiter, it concatenates the input elements, separated by the specified delimiter, in encounter order.
  • Collector<CharSequence,?,String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)- This method concatenates the input elements, separated by the specified delimiter, with the specified prefix and suffix, in encounter order.

Collectors.joining() Java Stream API examples

1. In this example we’ll pass a character array as a stream to the collect method where Collectors.joining() method is used to get a single string concatenating all the characters of the character array.

import java.util.stream.Collectors;
import java.util.stream.Stream;

public class JoiningDemo {

  public static void main(String[] args) {
    char[] ch = { 'T', 'h', 'i', 's', ' ',
                  'i', 's', ' ',
                  'S', 't', 'r', 'i', 'n', 'g' };
    String str1 = Stream.of(ch).map(c->new String(c)).collect(Collectors.joining());
    System.out.println("Concatenated String- " + str1);
  }
}
Output
Concatenated String- This is String

2. In this example we’ll pass an array of String as a Stream to the collect method to get a single string. We’ll also use the joining method where delimiter is passed as an argument.

public class JoiningDemo {

  public static void main(String[] args) {
    String[] strArr = { "This", "is", "a", "String" };
    String str1 = Stream.of(strArr).collect(Collectors.joining());
    System.out.println("Concatenated String- " + str1);
    
    // Passing Space as delimiter
    String str2 = Stream.of(strArr).collect(Collectors.joining(" "));
    System.out.println("Concatenated String with delimiter- " + str2);
    // Passing pipe as delimiter
    str2 = Stream.of(strArr).collect(Collectors.joining("|"));
    System.out.println("Concatenated String with delimiter- " + str2);
    
    // Passing delimiter, suffix and prefix
    String str3 = Stream.of(strArr).collect(Collectors.joining("|", "[", "]"));
    System.out.println("Concatenated String with delimiter and suffix, prefix- " + str3);
  }
}
Output
Concatenated String- ThisisaString
Concatenated String with delimiter- This is a String
Concatenated String with delimiter- This|is|a|String
Concatenated String with delimiter and suffix, prefix- [This|is|a|String]

3. In this example we’ll join the elements of an ArrayList using Collectors.joining() method of the Java Stream API.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JoiningDemo {

  public static void main(String[] args) {
    List<String> cityList = Arrays.asList("Delhi", "Mumbai", "London", "New York","Bengaluru");
    String str1 = cityList.stream().collect(Collectors.joining());
    System.out.println("Concatenated String- " + str1);
    
    // Passing Space as delimiter
    String str2 = cityList.stream().collect(Collectors.joining(" "));
    System.out.println("Concatenated String with delimiter- " + str2);
    // Passing pipe as delimiter
    str2 = cityList.stream().collect(Collectors.joining("|"));
    System.out.println("Concatenated String with delimiter- " + str2);
    
    // Passing delimiter, suffix and prefix
    String str3 = cityList.stream().collect(Collectors.joining("|", "[", "]"));
    System.out.println("Concatenated String with delimiter and suffix, prefix- " + str3);
  }
}
Output
Concatenated String- DelhiMumbaiLondonNew YorkBengaluru
Concatenated String with delimiter- Delhi Mumbai London New York Bengaluru
Concatenated String with delimiter- Delhi|Mumbai|London|New York|Bengaluru
Concatenated String with delimiter and suffix, prefix- [Delhi|Mumbai|London|New York|Bengaluru]

That's all for the topic Java Stream Collectors.joining() Method With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 24, 2024

Java Stream Collectors.groupingBy() Examples

In this tutorial we’ll see some examples of Collectors.groupingBy() method in Java Stream API. Collectors.groupingBy() method works similarly to "group by" statement in SQL which groups the elements as per the specified columns. This method also groups the elements according to the passed property and returns grouped result as a Map.

There are three overloaded Collectors.groupingBy() method-

  • Collector<T,?,Map<K,List>> groupingBy(Function<? super T,? extends K> classifier)- This method groups elements according to a classification function and returns the results in a Map. The collector produces a Map<K, List> where key specifies a group and List contains the elements which map to the associated key
  • Collector<T,?,Map<K,D>> groupingBy(Function<? super T,? extends K> classifier, Collector<? super T,A,D> downstream)- In this groupingBy() method first elements are grouped according to a passed classification function and then reduction operation is performed on the values associated with a given key using the Collector passed as second argument.
  • Collector<T,?,M> groupingBy(Function<? super T,? extends K> classifier, Supplier mapFactory, Collector<? super T,A,D> downstream)- In this variant first elements are grouped according to a passed classification function then reduction operation is performed on the values associated with a given key using the Collector passed as second argument. The resulting Map produced by the Collector is created with the supplied factory function.

Note that the returned Collector, in all the above methods, is not concurrent. There is a groupingByConcurrent() method with the same 3 overloaded methods which may offer better parallel performance. In case of groupingByConcurrent() methods a ConcurrentMap is returned.

Collectors.groupingBy() Java examples

For the example we’ll use the objects of the Student class.

public class Student {
  private int rollNo;
  private String name;
  private String stream;
  private int marks;
  Student(int rollNo, String name, String stream, int marks){
    this.rollNo = rollNo;
    this.name = name;
    this.stream = stream;
    this.marks = marks;
  }
  public int getRollNo() {
    return rollNo;
  }
  public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getStream() {
    return stream;
  }
  public void setStream(String stream) {
    this.stream = stream;
  }
  public int getMarks() {
    return marks;
  }
  public void setMarks(int marks) {
    this.marks = marks;
  }
}

1. If we need to group student according to the subject stream we can use the first Collectors.groupingBy() method where only a single argument classifier function is passed.

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, List<Student>> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream));
    // Iterating the returned Map
    names.entrySet().forEach(es->{System.out.println("Stream- " + es.getKey());
    System.out.println("**Students**");
    es.getValue().forEach(e->System.out.println(e.getName()));});

  }
}
Output
Stream- Art
**Students**
Priscilla
Mahesh
Stream- Science
**Students**
Peter
Ram
Stream- Commerce
**Students**
Scott

2. If you want the count of students in each stream then you need to group student according to the subject stream and also pass Collectors.counting() (which returns a collector) as a second argument.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, Long> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream, Collectors.counting()));

    names.entrySet().forEach(es-> {
              System.out.println("Stream- " + es.getKey() + 
                  " Number of Students- " + es.getValue());
              });
  }
}
Output
Stream- Art Number of Students- 2
Stream- Science Number of Students- 2
Stream- Commerce Number of Students- 1

3. If you want the Max marks in each stream then you need to group student according to the stream and also pass Collectors.maxBy (which returns a collector) as a second argument.

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, Optional<Student>> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream, Collectors.maxBy(Comparator.comparingInt(Student::getMarks))));

    names.entrySet().forEach(es-> {
              System.out.println("Stream- " + es.getKey() + 
                  " Student Name- " + es.getValue().get().getName() +
                  " Marks- " + es.getValue().get().getMarks());
              });
  }
}
Output
Stream- Art Student Name- Priscilla Marks- 68
Stream- Science Student Name- Ram Marks- 99
Stream- Commerce Student Name- Scott Marks- 72

4. If you want sorting to be done by keys you can return a TreeMap as a result of using groupingBy() method. In that case you have to pass one more argument which is of type Supplier and acts as a factory function.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class GroupingDemo {

  public static void main(String[] args) {
    List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
            new Student(2, "Ram", "Science", 99),
            new Student(3, "Priscilla", "Art", 68),
            new Student(4, "Mahesh", "Art", 62),
            new Student(5, "Scott", "Commerce", 72));
    Map<String, Set<String>> names = studentList.stream()
        .collect(Collectors.groupingBy(Student::getStream, TreeMap::new, Collectors.mapping(Student::getName, Collectors.toSet())));

    names.entrySet().forEach(es-> {
              System.out.println("Stream- " + es.getKey());
              System.out.println("**Students**");
                es.getValue().forEach(name -> System.out.println(name));
                });
  }
}
Output
Stream- Art
**Students**
Priscilla
Mahesh
Stream- Commerce
**Students**
Scott
Stream- Science
**Students**
Peter
Ram

Collectors.groupingByConcurrent() Java example

1. If you need to group student according to the stream in parallel we can use the Collectors.groupingByConcurrent() method where only a single argument classifier function is passed.

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

public class GroupingDemo {

    public static void main(String[] args) {
        List<Student> studentList = Arrays.asList(new Student(1, "Peter", "Science", 75),
                new Student(2, "Ram", "Science", 99),
                new Student(3, "Priscilla", "Art", 68),
                new Student(4, "Mahesh", "Art", 62),
                new Student(5, "Scott", "Commerce", 72));
        ConcurrentMap<String, List<Student>> names = studentList.parallelStream()
            .collect(Collectors.groupingByConcurrent(Student::getStream));
        // Iterating the returned Map
        names.entrySet().forEach(es->{System.out.println("Stream- " + es.getKey());
        System.out.println("**Students**");
        es.getValue().forEach(e->System.out.println(e.getName()));});

    }
}

That's all for the topic Java Stream Collectors.groupingBy() Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 21, 2024

ExpressJS Query Parameters

In this article we'll see how to use query parameters in ExpressJS web application. Generally, you use route parameters when you want to pass a specific resource like id. For example, http://ROOT_URL/api/user/1, here 1 is the userId. On the other hand, you'll use query parameters when you want to execute some functionality like sorting, filtering, paginating based on the passed query strings.

What is a query parameter

You get query string by adding query parameters to the URL after a question mark (?). These query strings are added in the form of (key, value) pairs.

For example http://ROOT_URL/products?limit=10&page=2, here limit and page are query parameters with value as 10 for limit and 2 for page. From the URL itself it is clear that you are using pagination to display products and you have to display page number 2 and number of records to be displayed are 10.

Route definition for query parameters

In your route definition you don't need to add any extra information for query parameters. For example, if you are adding query string after /products in your app URL your route definition will still be ('/products').

router.get('/products', productController.getProducts);

Retrieving query parameters

The values passed for the route parameters are populated in the req.query object, with the name of the query parameter as their respective keys and value of the query parameter as the property value.

For example, if the user makes a get request with http://ROOT_URL/products?limit=10&page=2 then req.query object would look like as given below-

req.query: { limit: '10', page: '2' }

and you can access individual query parameters like this-

const limit = req.query.limit;
const pageNum = req.query.page;

Query parameters Express.js example

This example shows the use of query parameter in Express.js by having a pagination logic for displayed products. In the URL, page number and limit query parameters are added to get the records as per the values passed for query parameters.

Example code is divided into route, controller and model folders with respective files in each of these directories.

routes\products.js

const express = require('express');
const router = express.Router();

const productController = require('../controllers/product');

router.get('/products', productController.getProducts);

module.exports = router;

For routing express.Router() is used to keep routing separate from application logic. There is a get request mapping for '/products' path and the callback function is kept in controllers\product.js file.

controllers\product.js

const Product = require('../models/product');

exports.getProducts = (req, res) => {
    console.log('In controller-', req.query);
    // TODO- do a check for whether value is passed
    const limit = req.query.limit;
    const pageNum = req.query.page;
    const products = Product.getProducts(limit, pageNum);
    res.status(200).send(products);
}

As you can see query parameters are extracted in the getProducts() function and passed as parameters to Product.getProducts() method which is in models directory.

models\product.js

module.exports = class Product {
    static getProducts(limit, pageNum){
        // Some hardcoded products
        const product = [{"id":"1","title":"Laptop", "price":"600"},
            {"id":"2","title":"RAM", "price":"100"}, 
            {"id":"3","title":"Mouse", "price":"50"}, 
            {"id":"4","title":"Keyboard", "price":"120"}];
        // Using array.slice to get the required products
        return product.slice((pageNum - 1) * limit, pageNum * limit);
    }
}

Since the focus is on query parameters so the records are hardcoded here rather than going to the DB. Array.slice() method is used to get the required records that fulfil the pagination criteria.

app.js

const express = require('express');
const app = express();

const port = 3000;
const productRouter = require('./routes/products');
app.use(productRouter);

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

With these files done if you run app.js file and access the URL- http://localhost:3000/products?limit=2&page=2

ExpressJS Query Parameters

That's all for the topic ExpressJS Query Parameters. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 18, 2024

Express res.sendFile() Method With Examples

In an ExpressJS application if you want to transfer the file at the given path then that can be done using response.sendFile() method. There is a similar method res.download() in Express.js which sends a file for download, difference between these two methods is that with res.sendFile() file is displayed by the browser whereas with res.download() browser prompts to download the sent file.

res.sendFile() method in Express.js

This method transfers the file at the given path and sets the Content-Type response HTTP header field based on the filename's extension.

res.sendFile() syntax

res.sendFile(path, options, fn)
  • path- absolute path to the file. It can be just the filename if root option is set in the options object.
  • options- This is an optional parameter to set properties like root, headers and many more. See the list of available options here- https://expressjs.com/en/4x/api.html#res.sendFile
  • fn- A callback function which is invoked when the transfer is complete or when an error occurs. Takes one parameter err which encapsulates the error.

res.sendFile example in Express.js

1. Sending an HTML file

If you want to send file views/person.html with in project root directory and the code is in examples/sendfile.js

views/person.html

<!DOCTYPE html>
<html>
<head>
    <title>Person Form</title>
</head>
<body>
    <form action="/savePerson" method="post">
        <label for="name">Enter Name</label>
        <input type="text" name="name">
        <br/>
        <label for="email">Enter email</label>
        <input type="text" name="email">
        <br/>
        <button type="submit">Submit</button>
    </form>
</body>

examples/sendfile.js

const express = require('express');
const app = express();
const path = require('path');
const port = 3000;
app.get('/', (req, res) => {
    const options = {
        root: path.join(__dirname, '..', 'views'),
        headers: {
          'x-timestamp': Date.now()
        }
    }
    const fileName = 'person.html';
    res.sendFile(fileName, options, (err)=>{
        if(err){
            console.error('Error while sending file:', err);
        }else{
            console.log('file ' + fileName + ' sent successfully');
        }
    })
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
});

As you can see, as the first parameter to sendFile() only the file name is passed. That is done because root property is set in options object.

root: path.join(__dirname, '..', 'views')

What it is doing is to go one level up from the current directory and then go to views directory.

On running the file and accessing the URL- http://localhost:3000 you should see the person.html file displayed.

2. Sending an image

Same way if you want to send an image named testimage.png residing in /public/images directory.

const express = require('express');

const app = express();

const path = require('path');

const port = 3000;

app.get('/', (req, res) => {
    const options = {
        root: path.join(__dirname, '..', 'public', 'images'),
        headers: {
          'x-timestamp': Date.now()
        }
    }
    const fileName = 'testimage.png';
    res.sendFile(fileName, options, (err)=>{
        if(err){
            console.error('Error while sending file:', err);
        }else{
            console.log('file ' + fileName + ' sent successfully');
        }
    })
})


app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
});

On running the file and accessing the URL- http://localhost:3000 you should see the image displayed.

That's all for the topic Express res.sendFile() Method With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 17, 2024

Express Route Parameters - Creating Dynamic URL

A very common scenario while creating REST APIs is to send user input as a part of URL means creating a dynamic URL in your express application. For example, user wants to search a user by ID and userID is passed as part of the URL (Like this- http://ROOT_URL/api/user/1, here 1 is the userId). In this post, you'll learn how to create dynamic routes in Express.js application using route parameters and how to retrieve route parameters.

Route parameters in Express.js

Route parameters act as a placeholder in route definitions and you can create them by using colon (:) which is followed by a meaningful name. For example, if you want to pass userId as part of the URL and you want it to be a dynamic URL then route definition for the same can be defined as-

app.get('/api/users/:userId', (req, res) => {
  const userId = req.params.userId;
  // Logic for finding the user with the passed userId
});

In the route definition '/api/users/:userId', :userId is the route parameter which acts as a placeholder for any passed userId.

If user makes a get request with http://ROOT_URL/api/users/1 then userId parameter will have the value 1.

If user makes a get request with http://ROOT_URL/api/users/112 then userId parameter will have the value 112.

Passing multiple route parameters

There can be multiple route parameters in a route definition.

app.get('api/authors/:authorId/posts/:postId', (req, res) => {
  const authorId = req.params.authorId;
  const postId  = req.params.postId;
  ...
  ...
})

If user makes a get request with http://ROOT_URL/api/authors/3/posts/127 then authorId will have the value 3 and postId will have the value 127.

Retrieving Route parameters

The values passed for the route parameters are populated in the req.params object, with the name of the route parameter specified in the path as their respective keys.

For example, if the route definition is- 'api/authors/:authorId/posts/:postId' and user makes a get request with http://ROOT_URL/api/authors/3/posts/127 then req.params object would look like as given below-

req.params: { "authorId ": "3", "postId": "127" }

Route parameters Express.js example

This example shows the use of route parameter in Express.js by having a dynamic URL where the userId part is dynamic. Application should search for the user with the passed userId and send back user data as response.

To keep it simple user data is hardcoded in a file.

data\userdata.js

const users = [
    { id: 1, name: 'Anil' },
    { id: 2, name: 'Stevens' },
    { id: 3, name: 'Roberto' },
    { id: 4, name: 'Preeti' }
]

module.exports = users;

Route definitions are created in a separate file using Express.router() to keep routing separate.

routes\users.js

const express = require('express');
const router = express.Router();

const users = require('../data/userdata');

router.get('/', function(req, res, next) {
  res.send('Visit /api/users/:userId to get user data');
});

router.get('/api/users/:userId', (req, res) => {
  console.log(req.params);
  const userId = parseInt(req.params.userId);
  console.log(users);
  const user = users.find(user => user.id === userId);
  if (!user) {
    return res.status(404).send('User not found')
  }
  res.json(JSON.stringify(user));
});

module.exports = router;

As you can see route parameter 'userId' is used in this route definition- '/api/users/:userId'. So userId acts as a placeholder which is replaced by the actual userId.

Route parameters are of type string by default so it should be converted to an integer, that's why parseInt() function is used.

const userId = parseInt(req.params.userId);

Once the userId is retrieved, find() method of the array is used to find the user with the matching id, if found then the user data is sent as JSON data. If user data is not found then status code '404' is sent with a custom message.

Finally, the app.js file which uses the router definition.

const express = require('express');
const app = express();

const port = 3000;

const usersRouter = require('./routes/users');
app.use(usersRouter);


app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

module.exports = app;

After running the app if you access URL- http://localhost:3000/api/users/4 you will get the user data for the user with id as 4.

{"id":4,"name":"Preeti"}

If you access - http://localhost:3000/api/users/2

{"id":2,"name":"Stevens"}

If you access- http://localhost:3000/api/users/10 (userId which doesn't exist)

User not found

If you access root URL- http://localhost:3000/

Visit /api/users/:userId to get user data

It is because of the following route definition in routes\users.js

router.get('/', function(req, res, next) {
  res.send('Visit /api/users/:userId to get user data');
});

That's all for the topic Express Route Parameters - Creating Dynamic URL. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 11, 2024

Express File Download Using res.download()

In your Express.js web application if you want to provide a functionality to download a file then that can be done by using response.download() method.

res.download() method in Express.js

Syntax of res.download() method is as given below-

res.download(path [, filename] [, options] [, fn])
  • path- Transfers the file at path as an "attachment". Typically, browsers will prompt the user for download.
  • Options- Optional parameters that can be passed. See the list of available options here- http://expressjs.com/en/5x/api.html#res.download
  • fn- Callback function that is called when the transfer is complete or when an error occurs. Takes one parameter err which encapsulates the error.

res.download() examples in Express.js and Node.js

This example shows how to download a .png image stored under /public/docs folder with in the project directory.

Downloading an image

var express = require('express');
var path = require('path');

var app = express();
const port = 3000;

app.get('/', function (req, res) {
    res.download(path.join(__dirname, "/public/docs/", "testimage.png"), (err) => {
        if (err) {
            console.log("Error : ", err);
            res.send("Problem downloading the file");
        }else{
            console.log('Document download done..');
        }
    });
});

//Server
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

Once you run the file and access URL http://localhost:3000/ browser should prompt you to download the file.

Downloading a PDF

You can download a pdf document too the same way.

var express = require('express');
var path = require('path');

var app = express();
const port = 3000;

app.get('/', function (req, res) {
    res.download(path.join(__dirname, "/public/docs/", "testdoc.pdf"), (err) => {
        if (err) {
            console.log("Error : ", err);
            res.send("Problem downloading the file");
        }else{
            console.log('Document download done..');
        }
    });
});

//Server
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

That's all for the topic Express File Download Using res.download(). If something is missing or you have something to share about the topic please write a comment.


You may also like

Using express-generator to Create ExpressJS App Structure

Express.js is a popular Node.js web framework. Because of its support for routing and view engines it makes it easy to create web applications using Express.js. One other tool that can make life easy is the express-generator which is an express application generation tool that can quickly create an application skeleton.

Using express-generator

Using express-generator you can quickly create a standard project structure for you ExpressJS application by using a single command.

express-generator Installation

You can install express-generator globally using the following command. Ensure you already have Node.js and Express.js installed in your system.

npm install -g express-generator
or by using
npx express-generator

Once express-generator is installed you can create an Express.js app by using the command as given below.

express EXPRESSJSAPP_NAME

For example, running the command

>express myexpressapp

creates an Express app named myexpressapp. The app will be created in a folder named myexpressapp in the current working directory. Note that by default the selected view engine is Jade and the stylesheet engine support defaults to plain CSS.

You can change the above-mentioned defaults by using the following options-

  • -v, --view <engine> add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
  • -c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)

For example, if you want to use ejs as view engine then you can use the following command to generate a project structure accordingly.

>express --view=ejs myexpressapp

create : myexpressapp\
create : myexpressapp\public\
create : myexpressapp\public\javascripts\
create : myexpressapp\public\images\
create : myexpressapp\public\stylesheets\
create : myexpressapp\public\stylesheets\style.css
create : myexpressapp\routes\
create : myexpressapp\routes\index.js
create : myexpressapp\routes\users.js
create : myexpressapp\views\
create : myexpressapp\views\error.ejs
create : myexpressapp\views\index.ejs
create : myexpressapp\app.js
create : myexpressapp\package.json
create : myexpressapp\bin\
create : myexpressapp\bin\www

change directory:
 > cd myexpressapp

install dependencies:
 > npm install

run the app:
 > SET DEBUG=myexpressapp:* & npm start

As given in the instructions change location to the generated project directory

D:\knpcode>cd myexpressapp

and run the command

D:\knpcode\myexpressapp>npm install

This will install all the project dependencies (Refer the generated package.json for the project dependencies).

Following image shows the generated project structure.

Running the application

Generated app has some basic routing and views already existing so you can run the app and see a view.

Run the following command to start the server

D:\knpcode\myexpressapp>npm start

Default port number is 3000 so you can access the application by using http://localhost:3000 that gives the following view.

Let's go through the project flow to understand how we reach this view.

Mapping to the root ('/') is in routes/index.js file.

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

module.exports = router;

As you can see get mapping for root renders the index.ejs file by using the res.render() method in its callback.

This index.ejs file is located in views folder.

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <h1><%= title %></h1>
    <p>Welcome to <%= title %></p>
  </body>
</html>

app.js is the main file which sets the view engine as ejs and sets the routes defined in routes folder.

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

View engine setup is done in these lines

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

Route setup is done in these lines-

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

app.use('/', indexRouter);
app.use('/users', usersRouter);

That's all for the topic Using express-generator to Create ExpressJS App Structure. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 7, 2024

ExpressJS res.render() Function

In an ExpressJS application if you want to render a view created using HTML templates then that can be done using response.render() function.

In ExpressJS, response.render() renders a view and sends the rendered HTML string to the client.

Syntax

res.render(view, locals, callback)
  • view- A string that is the file path of the view file to render.
  • locals- An object whose properties define local variables for the view. This is an optional parameter.
  • callback- A callback function, it is an optional parameter. callback function takes two arguments error and rendered string.

res.render() example in Express

We are going to use EJS template engines for JavaScript so we need to install EJS which can be done using the following command.

npm install ejs

You can set EJS as templating engine in your application using the following command.

app.set('view engine', 'ejs');

EJS, by default, looks for HTML templates in the views directory in the application root directory. So, let's create a 'views' directory and then create a 'home.ejs' file there with the following code.

views\home.ejs

<h3>Welcome to my site <%= siteName %></h3>

app.js

This file has the code to render the above template.

const express = require('express');
const app = express();
const port = 3000;

app.set('view engine', 'ejs');

app.get('/', (req, res) => {
    // render template
    res.render('home', {siteName: 'knpcode.com'});
})

//Server
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

Important points to note here-

  1. In res.render(), first argument is the view name which is set as ‘home’. By default, it will look in views folder and view engine is set as ejs so the view resolves to views/home.ejs
  2. There is one variable in the view- siteName. Using second argument, an object whose properties define values for the variables is set.

res.render() with callback function

You can also pass a third argument, a callback function, in res.render() method. With the callback you can intercept the rendered template before sending it. That gives you a chance to change the HTML in anyway you want before sending back the response.

const express = require('express');

const app = express();
const port = 3000;

app.set('view engine', 'ejs');

app.get('/', function(req, res){
    // render template
    res.render('home', {siteName: 'knpcode.com'}, (err, html) => {
        console.log(html);
        res.send(html);
    }); 
});

//Server
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

If you run the application then you should be able to see the rendered template in the console too because that is done in the callback.

node app.js
Example app listening on port 3000
<h3>Welcome to my site knpcode.com</h3>

That's all for the topic ExpressJS res.render() Function. If something is missing or you have something to share about the topic please write a comment.


You may also like

June 5, 2024

ExpressJS Redirect Using res.redirect()

In a web application you may have many pages and based on some event (like clicking submit button) you want the user to move from one page to another. To do that redirect is used and that's the topic of this article how to redirect from one URL to another or from one path to another in Express.

Redirect in ExpressJS

In ExpressJS response.redirect() method is used to redirect user to another URL.

response.redirect() syntax
res.redirect(status, path)
  • path- Redirects to the URL derived from the specified path
  • status- An optional parameter to send a HTTP status code. Default status code is "302" (Found).

res.redirect() usage examples

1. Redirects can be a fully-qualified URL for redirecting to a different site:

res.redirect('http://knpcode.com')

2. Redirects can be relative to the root of the host name. For example, if the application is on http://knpcode.com/admin/post/new, the following would redirect to the URL http://knpcode.com/admin:

res.redirect('/admin')

3. Redirects can be relative to the current URL. For example, from http://knpcode.com/admin/ (path with a trailing slash), the following would redirect to the URL http://knpcode.com/admin/post/new.

res.redirect('post/new')

4. You can also use '..' which means one level up for redirect. If you were on http://knpcode.com/admin/post/new, the following would redirect to http://knpcode.com/admin/post:

res.redirect('..')

res.redirect example in Express

1. This example shows redirect to another path.

const express = require('express');

const app = express();
const port = 3000;

app.get('/', function(req, res){
    console.log('Redirecting to home page...');
    // redirect to another path
    res.redirect('/home');
})


app.get('/home', function(req, res){
    res.send("<h3>Welcome to my site</h3>");
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

If you run the application and access URL http://localhost:3000 it should redirect you to http://localhost:3000/home

2. Redirect to another fully qualified URL

const express = require('express');
const app = express();
const port = 3000;

app.get('/', function(req, res){
    console.log('Redirecting to another URL...');
    // redirect to another URL
    res.redirect('http://knpcode.com');
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

That's all for the topic ExpressJS Redirect Using res.redirect(). If something is missing or you have something to share about the topic please write a comment.


You may also like

June 4, 2024

Express body-parser With Examples

ExpressJS body-parser is a body parsing middleware which parses incoming request bodies.

You can use body-parser module when you need to parse form data sent by a user by submitting a web form, to parse JSON payloads in REST APIs.

Installing body-parser

You can install body-parser module by using the following command.

npm install body-parser

Parsers in body-parser

This module provides the following parsers-

  1. JSON body parser- For parsing JSON. Though there is a built-in middleware express.json() which can do the same task.
  2. URL-encoded form body parser- Parses urlencoded bodies (form data - application/x-www-form-urlencoded)
  3. Raw body parser- Parses request body as a Buffer
  4. Text body parser- Parses request body as a string

body-parser middleware example with ExpressJS

In the example there is a form which has name and email inputs and submit button to submit the form.

This form is parsed using body-parser in a POST request. There is another route for JSON parser.

views\person.html

<!DOCTYPE html>
<html>
<head>
    <title>Person Form</title>
</head>
<body>
    <form action="/savePerson" method="post">
        <label for="name">Enter Name</label>
        <input type="text" name="name">
        <br/>
        <label for="email">Enter email</label>
        <input type="text" name="email">
        <br/>
        <button type="submit">Submit</button>
    </form>
</body> 

The example uses express.Router() to create modular route definitions.

routes\routes.js

There are 3 route definitions. First is get request for rendering the html file for root path.

There is a POST request for the route '/savePerson' which uses bodyParser.urlencoded()

There is a POST request for the route '/api/Person' which uses bodyParser.json()

const express = require('express');
const path = require('path');
const router = express.Router();

router.get('/', (req, res) => {
    const view = path.join(__dirname, '..', 'views', 'person.html');
    res.sendFile(view);
})

router.post('/savePerson', (req, res) => {
    const name = req.body.name;
    console.log(name);
    const email = req.body.email;
    console.log(email);
    res.send('<h3>Your name is ' + name + ' and email is ' + email + '</h3>');
})

router.post('/api/Person', (req, res) => {
    const name = req.body.name;
    console.log(name);
    const email = req.body.email;
    console.log(email);
    // Then Logic to save Person data

    res.status(201).send("Data Saved Successfully");

})

module.exports = router;

app.js

This is the file where route definitions are imported. You'll import 'body-parser' too to parse the request body.

const express = require('express');

const appRoutes = require('./routes/route')

const bodyParser = require('body-parser'); 

const app = express();
const port = 3000;

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: true}));

// parse application/json
app.use(bodyParser.json())

// routes
app.use(appRoutes);
//Server
app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

Run the application using the following command

node app.js

If application starts successfully access the URL localhost:3000 which should render a form.

bodyParser.urlencoded

On submitting the form

Express body-parser

In the console you should see the logs too

node app.js
Example app listening on port 3000
TestUser
TestUser@tu.com

For the other route you can use Postman to create a POST request with the JSON body.

{
    "name": "Suresh",
    "email": "suresh@su.com"
}

That's all for the topic Express body-parser With Examples. If something is missing or you have something to share about the topic please write a comment.


You may also like