Node.js API compatibility - Url

The url module in Node.js provides utilities for URL resolution and parsing. It allows developers to work with URLs in a structured way, making it easier to manipulate and extract information from them. This module is essential for web applications that need to handle URLs for routing, API requests, and more. It’s available in the Azion Runtime through Node.js compatibility, so functions can parse the incoming request URL, read query parameters, and build new URLs when proxying or redirecting traffic.


Example: URL parsing and formatting

The example below shows how to use the url module in a function:

/**
* An example of using Node.js URL API in an Azion Function.
* Support:
* - Partially supported (Extended by library `url`)
* @module runtime-apis/nodejs/url/main
* @example
* // Execute with Azion Bundler:
* npx edge-functions build
* npx edge-functions dev
*/
import url from "node:url";
/**
* An example of using the Node.js URL API in an Azion Function.
* @param {*} event
* @returns {Promise<Response>}
*/
const main = async (event) => {
/**
* URL globalThis object
* https://developer.mozilla.org/en-US/docs/Web/API/URL
* if use URL in the browser, don't need to import
*/
const newUrl = new URL("https://example.com/some/path?format=json&page=1");
console.log("newURL", newUrl);
const urlFormated = url.format({
protocol: "https",
hostname: "example.com",
pathname: "/some/path",
query: {
page: 1,
format: "json",
},
});
console.log(url.parse(urlFormated));
return new Response("Done!", { status: 200 });
};
export default main;

Example: Request URL parsing

Parse incoming request URLs to extract routing information:

// url module imported for legacy API demonstration
// new URL() and URLSearchParams are available globally
import url from "node:url";
const main = async (event) => {
const request = event.request;
const requestUrl = new URL(request.url);
// Extract URL components
const urlInfo = {
href: requestUrl.href,
origin: requestUrl.origin,
protocol: requestUrl.protocol,
hostname: requestUrl.hostname,
port: requestUrl.port,
pathname: requestUrl.pathname,
search: requestUrl.search,
hash: requestUrl.hash
};
// Parse query parameters
const searchParams = requestUrl.searchParams;
const queryParams = {};
for (const [key, value] of searchParams) {
queryParams[key] = value;
}
// ⚠️ url.parse() is deprecated since Node.js v11.0.0
// Prefer the WHATWG URL API (new URL()) shown above
const parsedUrl = url.parse(request.url, true);
console.log("Parsed URL:", parsedUrl);
// Get path segments
const segments = requestUrl.pathname.split("/").filter(Boolean);
return new Response(JSON.stringify({
urlInfo,
queryParams,
segments,
parsedQuery: parsedUrl.query
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: Building URLs dynamically

Construct URLs for API calls and redirects:

import url from "node:url";
const main = async (event) => {
// Build API URL with query parameters
const apiUrl = new URL("https://api.example.com/v1/users");
apiUrl.searchParams.set("page", "1");
apiUrl.searchParams.set("limit", "10");
apiUrl.searchParams.set("sort", "name");
apiUrl.searchParams.set("active", "true");
console.log("API URL:", apiUrl.toString());
// Build redirect URL
const redirectUrl = url.format({
protocol: "https",
hostname: "app.example.com",
pathname: "/dashboard",
query: {
ref: "login",
session: "abc123"
}
});
// Resolve relative URL
// ⚠️ url.resolve() is deprecated since Node.js v11.0.0
// Prefer: new URL(relativePath, baseUrl).href
const baseUrl = "https://example.com/docs/";
const relativePath = "../api/reference";
const resolvedUrl = url.resolve(baseUrl, relativePath);
console.log("Resolved URL (deprecated):", resolvedUrl);
// Modern alternative using URL constructor
const modernResolvedUrl = new URL(relativePath, baseUrl).href;
console.log("Resolved URL (modern):", modernResolvedUrl);
// Build URL from parts
const parts = {
protocol: "https:",
hostname: "cdn.example.com",
port: "443",
pathname: "/assets/images/logo.png"
};
const fullUrl = url.format(parts);
return new Response(JSON.stringify({
apiUrl: apiUrl.toString(),
redirectUrl,
resolvedUrl,
builtUrl: fullUrl
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: URLSearchParams manipulation

Work with query string parameters efficiently:

import url from "node:url";
const main = async (event) => {
const requestUrl = new URL(event.request.url);
const params = requestUrl.searchParams;
// Read parameters
const page = params.get("page") || "1";
const limit = params.get("limit") || "10";
const sort = params.get("sort");
console.log("Page:", page, "Limit:", limit, "Sort:", sort);
// Check if parameter exists
const hasFilter = params.has("filter");
console.log("Has filter:", hasFilter);
// Get all values for a parameter (multi-value)
const tags = params.getAll("tag");
console.log("Tags:", tags);
// Modify parameters
params.set("page", "2");
params.set("timestamp", Date.now().toString());
params.delete("debug");
// Iterate over parameters
const allParams = [];
for (const [key, value] of params) {
allParams.push({ key, value });
}
// Sort parameters alphabetically
params.sort();
// Convert to string
const queryString = params.toString();
// Create new URLSearchParams from object
const newParams = new URLSearchParams({
format: "json",
version: "2",
pretty: "true"
});
return new Response(JSON.stringify({
originalParams: { page, limit, sort },
hasFilter,
tags,
modifiedParams: allParams,
queryString,
newParamsString: newParams.toString()
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: URL validation and normalization

Validate and normalize user-provided URLs:

import url from "node:url";
const main = async (event) => {
const request = event.request;
// Note: In a real application, you might receive URLs from the request body
// const { urls: customUrls } = await request.json().catch(() => ({}));
// URLs to validate
const testUrls = [
"https://example.com/path",
"http://localhost:3000/api?query=test",
"HTTPS://EXAMPLE.COM/UPPERCASE",
"https://example.com:443/standard-port",
"https://user:pass@example.com/auth",
"not-a-url",
"ftp://files.example.com"
];
const results = testUrls.map(testUrl => {
try {
const parsed = new URL(testUrl);
return {
original: testUrl,
valid: true,
normalized: parsed.href,
protocol: parsed.protocol,
hostname: parsed.hostname,
isHttps: parsed.protocol === "https:"
};
} catch (error) {
return {
original: testUrl,
valid: false,
error: error.message
};
}
});
// Normalize a URL (lowercase hostname, default port removal)
const normalizeUrl = (urlString) => {
try {
const parsed = new URL(urlString);
parsed.hostname = parsed.hostname.toLowerCase();
// Remove default ports
if (parsed.protocol === "https:" && parsed.port === "443") {
parsed.port = "";
}
if (parsed.protocol === "http:" && parsed.port === "80") {
parsed.port = "";
}
return parsed.href;
} catch {
return null;
}
};
const normalizedUrls = testUrls.map(normalizeUrl);
return new Response(JSON.stringify({
validationResults: results,
normalizedUrls
}), {
headers: { "Content-Type": "application/json" }
});
};
export default main;

Example: URL routing and path matching

Use URL parsing for request routing:

import url from "node:url";
const main = async (event) => {
const requestUrl = new URL(event.request.url);
const pathname = requestUrl.pathname;
// Define routes
const routes = {
"/": { handler: "home", methods: ["GET"] },
"/api/users": { handler: "users", methods: ["GET", "POST"] },
"/api/users/:id": { handler: "userDetail", methods: ["GET", "PUT", "DELETE"] },
"/api/products": { handler: "products", methods: ["GET"] },
"/health": { handler: "health", methods: ["GET"] }
};
// Match route
const matchRoute = (path) => {
// Exact match
if (routes[path]) {
return { ...routes[path], params: {} };
}
// Pattern match for :id style routes
for (const [pattern, config] of Object.entries(routes)) {
if (pattern.includes(":")) {
const regex = new RegExp("^" + pattern.replace(/:\w+/g, "([^/]+)") + "$");
const match = path.match(regex);
if (match) {
const paramNames = pattern.match(/:\w+/g) || [];
const params = {};
paramNames.forEach((name, i) => {
params[name.slice(1)] = match[i + 1];
});
return { ...config, params };
}
}
}
return null;
};
const matchedRoute = matchRoute(pathname);
const method = event.request.method;
// Check if method is allowed
const methodAllowed = matchedRoute?.methods?.includes(method);
// Build response
const response = {
pathname,
method,
matched: matchedRoute ? {
handler: matchedRoute.handler,
params: matchedRoute.params,
methodAllowed
} : null,
query: Object.fromEntries(requestUrl.searchParams)
};
return new Response(JSON.stringify(response, null, 2), {
status: matchedRoute && methodAllowed ? 200 : matchedRoute ? 405 : 404,
headers: { "Content-Type": "application/json" }
});
};
export default main;

Supported APIs

APIStatus
URL (global)🟢 Supported
URLSearchParams🟢 Supported
url.URL🟢 Supported
url.URLSearchParams🟢 Supported
url.format()🟢 Supported
url.parse()🟡 Deprecated (use new URL())
url.resolve()🟡 Deprecated (use new URL(relative, base))
url.domainToASCII()🟡 Partially supported
url.domainToUnicode()🟡 Partially supported
url.fileURLToPath()🟡 Partially supported
url.pathToFileURL()🟡 Partially supported
url.urlToHttpOptions()🟡 Partially supported