DEV Community

Julien Cavaleiro
Julien Cavaleiro

Posted on • Originally published at cavaleiro.fr

Exploration of Tagged template Literals

Hi, this is my first-ever blog post. I'm a French developer around Strasbourg. It's a repost from my website. Feel free to comment to help me improve my writing and my English (I'm still learning it).


Tagged template literal is a powerful feature of JS, standardized with ES2015,
and supported by most browser.

But, how does it work exactly?

It's a special function where you can add custom interpolation.


Interpolation example :

  • highlight text.
  • create custom CSS (see css-in-js solutions).
  • interpolate variables from SQL query (more below).

And here a custom tagged template function:

function myTaggedTemplate(parts, coolVariable) {
  console.log(parts)
  console.log(coolVariable)
}

myTaggedTemplate`Tagged template are ${"cool"}.`
// => ["Tagged template are ", "."]
// => cool

Great, but how do I do custom interpolation? 😁

Well, ok. I'm going to provide a better example. But before that, a bit more why I ended up with tagged template.

I'm working on a company which build an ERP. We are trying to modernize the core of it and make the modernization of it as simple as possible
for other employee.

In that research, we ended wanting to have a small wrapper around SQL because most employee who use our tools known SQL well
but not JS.


Merge query with user input is not a good idea to avoid SQL injection.


This is why we end up with tagged template. Tagged template isolate user input by default. And this is a wonderful feature.

The other interesting part : SQL driver already sanitize input for SQL command.
Since tagged template separate query from input, the work is done.

Here how it looks :

const { query, variables } = query`
  SELECT desc, unit, price
  from sales
  where status = ${"completed"} and customer_id = ${15735}
  order by created_at desc
`
// query => select desc, unit, price from sales where status = :0 order by created_at desc
// variables => ["completed", 15735]

completed and 15735 are inline here but that data came from user input.

And how it works :

// we use `...variables` because we don't know how many `${}` developers are going to use.

function query(parts, ...variables) {
  let query = ""
  // we need to concatenate the string parts.
  for (let i = 0, size = parts.length; i < size; i++) {
    query += parts[i]
    // if we have a variables for it, we need to bind it.
    if (variables[i]) {
      query += ":" + i
    }
  }

  return { query, variables }
}

The function split query from variables by default. And then, we can leverage on the SQL driver to make a safe query and avoid SQL injection.


The example right here is because I use oracle as a database at work. Other
drivers my expect something else then :0, :1, and so on.


Same example with execute from oracledb

const { query, variables } = query`
  SELECT desc, unit, price
  from sales
  where status = ${"completed"} and customer_id = ${15735}
  order by created_at desc
`
// connection object from oracledb
const result = await connection.execute(query, variables)

Pretty cool, uh?

Top comments (3)

Collapse
 
evanplaice profile image
Evan Plaice

FYI, I wrote a library that can be used to create a tagged template literal from raw text. For example, you can fetch the literal from an external file and load it using the lib.

github.com/vanillaes/interpolate

Collapse
 
juliencavaleiro profile image
Julien Cavaleiro

Interesting! What is your use case for it? Non ES6 engine?

Collapse
 
evanplaice profile image
Evan Plaice

Why introduce a new template syntax when JS already has a template syntax built-in?

For example, here's a web component that can fetch both the template and context (ie data) without the need to write any JS.

github.com/vanillawc/wc-template