Easy URL Parsing With Isomorphic JavaScript

Share this article

Most web applications require URL parsing whether it’s to extract the domain name, implement a REST API or find an image path. A typical URL structure is described by the image below: URL structure You can break a URL string into constituent parts using regular expressions but it’s complicated and unnecessary…

Server-side URL Parsing

Node.js (and forks such as io.js) provide a URL API:
// Server-side JavaScript
var urlapi = require('url'),
url = urlapi.parse('http://site.com:81/path/page?a=1&b=2#hash');

console.log(
url.href + '\n' + // the full URL
url.protocol + '\n' + // http:
url.hostname + '\n' + // site.com
url.port + '\n' + // 81
url.pathname + '\n' + // /path/page
url.search + '\n' + // ?a=1&b=2
url.hash // #hash
);
As you can see in the snippet above, the parse() method returns an object containing the data you need such as the protocol, the hostname, the port, and so on.

Client-side URL Parsing

There’s no equivalent API in the browser. But if there’s one thing browsers do well, it’s URL parsing and all links in the DOM implement a similar Location interface, e.g.:
// Client-side JavaScript
// find the first link in the DOM
var url = document.getElementsByTagName('a')[0];

console.log(
url.href + '\n' + // the full URL
url.protocol + '\n' + // http:
url.hostname + '\n' + // site.com
url.port + '\n' + // 81
url.pathname + '\n' + // /path/page
url.search + '\n' + // ?a=1&b=2
url.hash // #hash
);
If we have a URL string, we can use it on an in-memory anchor element (a) so it can be parsed without regular expressions, e.g.:
// Client-side JavaScript
// create dummy link
var url = document.createElement('a');
url.href = 'http://site.com:81/path/page?a=1&b=2#hash';

console.log(url.hostname); // site.com

Isomorphic URL Parsing

Aurelio recently discussed isomorphic JavaScript applications. In essence, it’s progressive enhancement taken to an extreme level where an application will happily run on either the client or server. A user with a modern browser would use a single-page application. Older browsers and search engine bots would see a server-rendered alternative. In theory, an application could implement varying levels of client/server processing depending on the speed and bandwidth capabilities of the device. Isomorphic JavaScript has been discussed for many years but it’s complex. Few projects go further than implementing sharable views and there aren’t many situations where standard progressive enhancement wouldn’t work just as well (if not better given most “isomorphic” frameworks appear to fail without client-side JavaScript). That said, it’s possible to create environment-agnostic micro libraries which offer a tentative first step into isomorphic concepts. Let’s consider how we could write a URL parsing library in a lib.js file. First we’ll detect where the code is running:
// running on Node.js?
var isNode = (typeof module === 'object' && module.exports);
This isn’t particularly robust since you could have a module.exports function defined client-side but I don’t know of a better way (suggestions welcome). A similar approach used by other developers is to test for the presence of the window object:
// running on Node.js?
var isNode = typeof window === 'undefined';
Let’s now complete our lib.js code with a URLparse function:
// lib.js library functions

// running on Node.js?
var isNode = (typeof module === 'object' && module.exports);

(function(lib) {

"use strict";

// require Node URL API
var url = (isNode ? require('url') : null);

// parse URL
lib.URLparse = function(str) {

if (isNode) {
return url.parse(str);
}
else {
url = document.createElement('a');
url.href = str;
return url;
}

}

})(isNode ? module.exports : this.lib = {});
In this code I’ve used an isNode variable for clarity. However, you can avoid it by placing the test directly inside the last parenthesis of the snippet. Server-side, URLparse is exported as a Common.JS module. To use it:
// include lib.js module
var lib = require('./lib.js');

var url = lib.URLparse('http://site.com:81/path/page?a=1&b=2#hash');
console.log(
url.href + '\n' + // the full URL
url.protocol + '\n' + // http:
url.hostname + '\n' + // site.com
url.port + '\n' + // 81
url.pathname + '\n' + // /path/page
url.search + '\n' + // ?a=1&b=2
url.hash // #hash
);
Client-side, URLparse is added as a method to the global lib object:
<script src="./lib.js"></script>
<script>
var url = lib.URLparse('http://site.com:81/path/page?a=1&b=2#hash');
console.log(
url.href + '\n' + // the full URL
url.protocol + '\n' + // http:
url.hostname + '\n' + // site.com
url.port + '\n' + // 81
url.pathname + '\n' + // /path/page
url.search + '\n' + // ?a=1&b=2
url.hash // #hash
);
</script>
Other than the library inclusion method, the client and server API is identical. Admittedly, this is a simple example and URLparse runs (mostly) separate code on the client and server. But we have implemented a consistent API and it illustrates how JavaScript code can be written to run anywhere. We could extend the library to offer further client/server utility functions such as field validation, cookie parsing, date handling, currency formatting etc. I’m not convinced full isomorphic applications are practical or possible given the differing types of logic required on the client and server. However, environment-agnostic libraries could ease the pain of having to write two sets of code to do the same thing.

Frequently Asked Questions (FAQs) on URL Parsing in Isomorphic JavaScript

What is URL parsing in Isomorphic JavaScript?

URL parsing in Isomorphic JavaScript refers to the process of dissecting a URL into its individual components, or parameters. This is done to extract specific information from the URL, such as the protocol, hostname, path, query string, and fragment identifier. Isomorphic JavaScript, also known as Universal JavaScript, is a type of JavaScript code that can run both on the client-side and the server-side. This makes it a versatile tool for URL parsing as it can handle this task regardless of where the code is executed.

How does URL parsing differ between client-side and server-side JavaScript?

The main difference lies in the methods and objects available for URL parsing. On the client-side, JavaScript has the built-in URL and URLSearchParams objects that can be used to parse URLs. On the server-side, Node.js provides the url module which contains methods for URL resolution and parsing. However, with Isomorphic JavaScript, you can use the same code for URL parsing on both the client-side and server-side.

What are the components of a URL that can be parsed in JavaScript?

A URL can be broken down into several components: the protocol (http or https), hostname (www.example.com), port (optional), pathname (/path/to/resource), query string (?key=value), and fragment identifier (#section). Each of these components can be extracted during the URL parsing process in JavaScript.

How can I extract the query parameters from a URL in JavaScript?

You can use the URLSearchParams interface to work with the query string of a URL. This interface provides methods to get the values of parameters, check if a parameter exists, iterate over all parameters, and more. Here’s a simple example:

let url = new URL('https://www.example.com/?key=value');
let params = new URLSearchParams(url.search);
console.log(params.get('key')); // "value"

How can I handle URL parsing in Node.js?

Node.js provides the url module for URL resolution and parsing. You can use the url.parse() method to break a URL string down into its components, or the url.format() method to construct a URL string from an object of components. Here’s an example:

const url = require('url');
let parsedUrl = url.parse('https://www.example.com/path?key=value#section');
console.log(parsedUrl.host); // "www.example.com"

What is the purpose of URL encoding and how can I perform it in JavaScript?

URL encoding is used to convert non-alphanumeric characters into a format that can be transmitted over the Internet. JavaScript provides the encodeURIComponent() function for this purpose. This function encodes special characters, as well as all characters that have a hexadecimal value greater than 7F.

How can I construct a URL from its components in JavaScript?

You can use the URL object to construct a URL from its components. The URL constructor takes two arguments: the URL (or path) and a base URL (optional). Here’s an example:

let url = new URL('/path?key=value#section', 'https://www.example.com');
console.log(url.href); // "https://www.example.com/path?key=value#section"

How can I handle relative and absolute URLs in JavaScript?

The URL object can be used to resolve relative URLs against a base URL. If you provide a relative URL as the first argument to the URL constructor and a base URL as the second argument, it will return an absolute URL.

How can I modify the query parameters of a URL in JavaScript?

You can use the URLSearchParams interface to modify the query parameters of a URL. This interface provides methods to add, delete, and update parameters. Here’s an example:

let url = new URL('https://www.example.com/?key=value');
let params = new URLSearchParams(url.search);
params.set('key', 'newValue');
url.search = params.toString();
console.log(url.href); // "https://www.example.com/?key=newValue"

How can I handle URL parsing errors in JavaScript?

You can use a try-catch block to handle errors that may occur during URL parsing. If an error occurs while creating a new URL object or calling a method of the URL or URLSearchParams interface, an exception will be thrown. You can catch this exception and handle it appropriately.

Craig BucklerCraig Buckler
View Author

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's created enterprise specifications, websites and online applications for companies and organisations including the UK Parliament, the European Parliament, the Department of Energy & Climate Change, Microsoft, and more. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler.

AurelioDisomorphicjavascriptLearn-Node-JSnode.js
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week