Written by Joe Attardi✏️
URLs are a critical piece of any web app. If your app makes requests to an API, it’s important to craft the correct URLs for these requests. The URL API, supported in all modern browsers, provides a way to parse and manipulate URLs. It provides easy access to the various parts of the URL.
Consider the following URL:
https://example.com/api/search?query=foo&sort=asc#results
This URL is made up of the following components:
With modern JavaScript, we can parse URLs and extract these different parts as needed.
In older browsers, before the URL API was available, one way that developers parsed URLs was by using an element. This element provides some basic URL parsing. For example, here is a way you could extract the query string from a URL:
function getQueryString(url) { const link = document.createElement('a'); link.href = url; return url.search; }
However, this approach has some disadvantages:
You could also use a regular expression to parse out the various parts of the URL, but this is tedious and error-prone.
Using the URL API to parse URLs is straightforward. Just pass the URL you want to parse to the URL constructor. If the URL string is valid, you’ll get a URL object back with properties for various parts of the URL:
const url = new URL('https://example.com/api/search?query=foobar'); console.log(url.host); // example.com console.log(url.pathname); // /api/search console.log(url.search); // ?query=foobar
You can access the query string of a URL in two ways:
If you’re interested in the value of a particular parameter in the query string, you can use its get method to get the parameter by its name:
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10'); console.log(url.searchParams.get('query'); // foobar console.log(url.searchParams.get('maxResults'); // 10
If there are multiple parameters with the same name, you can use getAll to get an array containing all of the values for that name:
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3'); console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']
Building a query string by hand can be tricky, especially if any query parameters contain special characters that need to be escaped. For example, if a query parameter needs to contain a & character, you’d need to encode it as &. To cover these situations, you need to use the encodeURIComponent function:
function getQueryString(url) { const link = document.createElement('a'); link.href = url; return url.search; }
You can build the query string more safely by using the URLSearchParams object:
const url = new URL('https://example.com/api/search?query=foobar'); console.log(url.host); // example.com console.log(url.pathname); // /api/search console.log(url.search); // ?query=foobar
Advantages of using URLSearchParams include:
Without a URLSearchParams object, it’s a little tricky to iterate over the parameters in a query string. You would need to split strings several times — first into groups of key/value pairs, then again to split up the key and value:
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10'); console.log(url.searchParams.get('query'); // foobar console.log(url.searchParams.get('maxResults'); // 10
If the parameters could contain encoded characters, you’d also need to decode them:
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3'); console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']
Instead, you can use URLSearchParams's entries method to iterate over the key/value pairs:
let queryString = 'foo=bar'; queryString += '&baz=qux'; queryString += '&tag=' + encodeURIComponent('one&two'); console.log(queryString); // foo=bar&baz=qux&tag=one%26two
Here’s a full example of building a URL with a base URL and some query parameters:
const params = new URLSearchParams(); params.append('foo', 'bar'); params.append('baz', 'qux'); params.append('tag', 'one&two'); console.log(params.toString()); // foo=bar&baz=qux&tag=one%26two
You might try using a regular expression to validate a URL, but it’s notoriously difficult to craft a regular expression that fully captures a valid URL string.
Instead, you can reach for the URL API. The URL constructor will throw an error if you give it an invalid URL. You can use this to check if a URL is valid:
function listQueryParams(queryString) { queryString.split('&').forEach(param => { const [key, value] = param.split('='); console.log(`${key}: ${value}`); }); }
With newer browsers, this is even easier. There’s a newer URL.canParse static method that performs similar validation with a single line of code. Like the isValidURL function above, it takes a potential URL string and returns true or false depending on the validity of the URL string.
The URL API has a powerful mechanism for resolving relative URLs. Normally, the argument to the URL constructor will throw an error if it’s not a full, valid URL. However, you can specify a second argument that serves as a base from which to build a relative URL. If you use the two-argument approach, the first argument doesn’t have to be a valid URL but the second one does.
Let’s look at a simple case first:
function listQueryParams(queryString) { queryString.split('&').forEach(param => { const [key, value] = param.split('='); console.log(`${key}: ${decodeURIComponent(value)}`); }); }
The URL constructor takes the base URL of https://example.com and adds the relative path /about, resulting in https://example.com/about.
What about this one:
function listQueryParams(queryString) { const params = new URLSearchParams(queryString); params.entries().forEach(([key, value]) => console.log(`${key}: ${value}`)); }
You might expect this to be https://example.com/users/profile, but it actually comes out to https://example.com/profile. This behaves just like a relative link; it takes the parent path segment, which is the root of example.com, and then adds profile.
Let’s look at one more example of using a relative URL. You can also use .. to go back up the path hierarchy:
function getQueryString(url) { const link = document.createElement('a'); link.href = url; return url.search; }
This one comes out to https://example.com/profile. Remember that relative URLs start at the parent path segment. Then, this one has .. in it, which goes up one more path segment.
If you call the URL constructor with a relative URL and specify an invalid or incomplete URL for the base URL, you’ll get an error. You’ll also get an error if you use a relative URL without a full base URL:
const url = new URL('https://example.com/api/search?query=foobar'); console.log(url.host); // example.com console.log(url.pathname); // /api/search console.log(url.search); // ?query=foobar
You might be familiar with the window.location object, which represents the current page’s URL. This object also has properties such as href and pathname, so you might think it’s a URL object. This is a different object, a Location, which has some properties in common with URL, but is also missing some (such as the searchParams property).
Even though it’s not a URL object, you can still use window.location to construct new URL objects. You can pass window.location to the URL constructor to create a new full-blown URL with searchParams and all, based on the current URL, or you can even use it as the base URL when constructing relative URLs:
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10'); console.log(url.searchParams.get('query'); // foobar console.log(url.searchParams.get('maxResults'); // 10
Using a URL makes it easy to get the path from a URL. For example, in the URL https://example.com/api/users/123/profile, the path name is /api/users/123/profile. What if we wanted to get just the user ID, 123, from this URL?
As we discussed earlier, it can be difficult to create proper regular expressions to validate and extract parts of a URL.
It’s not available in all browsers just yet, but you can use the URLPattern API to match and extract parts of the URL, matching patterns you specify. This can be particularly useful for things like client-side routing in a single-page application (SPA).
Using the user profile URL as an example, let’s create a URLPattern to get the user ID. We can use a leading : character to denote a named placeholder, which can be used later to match that part of the URL:
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3'); console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']
When you call exec on a URLPattern, it needs a valid URL. It returns a matcher object that contains properties for each of the URL’s parts (protocol, host, pathname, etc.). Each of these properties also has a groups property, which maps placeholder names like :userId to their values within the URL.
If you’re only concerned about matching one part of the URL, such as the path name as we’ve done here, you can specify wildcards in the URL pattern as well. Or, instead of a URL string, you can pass an object containing the parts of the URL you’re interested in matching:
let queryString = 'foo=bar'; queryString += '&baz=qux'; queryString += '&tag=' + encodeURIComponent('one&two'); console.log(queryString); // foo=bar&baz=qux&tag=one%26two
The URLPattern API is still not available in all browsers. At the time of writing, it’s not yet supported in Firefox or Safari. You can see the latest browser support information at CanIUse.com.
The URL API is a versatile interface for constructing, validating, and manipulating URLs in JavaScript. It’s safer and less error-prone to use than manual parsing or regular expressions. By using a URLSearchParams object, you can build a query string without worrying about string concatenation or encoding special characters.
The URLPattern API takes this a step further, supporting wildcards and named placeholders, so you can slice and dice URLs to meet your app’s needs! Further reading:
NPM:
function getQueryString(url) { const link = document.createElement('a'); link.href = url; return url.search; }
Script Tag:
const url = new URL('https://example.com/api/search?query=foobar'); console.log(url.host); // example.com console.log(url.pathname); // /api/search console.log(url.search); // ?query=foobar
3.(Optional) Install plugins for deeper integrations with your stack:
Get started now
The above is the detailed content of Working with URLs in JavaScript. For more information, please follow other related articles on the PHP Chinese website!