Compatibilidade APIs Node.js - Url

O módulo url no Node.js fornece utilitários para resolução e análise de URLs. Ele permite que desenvolvedores trabalhem com URLs de forma estruturada, facilitando a manipulação e extração de informações delas. Este módulo é essencial para aplicações web que precisam lidar com URLs para roteamento, requisições de API e mais. Está disponível no Azion Runtime através da compatibilidade com Node.js, permitindo que functions analisem a URL da requisição recebida, leiam parâmetros de consulta e construam novas URLs ao fazer proxy ou redirecionar tráfego.


Exemplo: Análise e formatação de URL

O exemplo abaixo mostra como usar o módulo url em uma 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;

Exemplo: Análise de URL de requisição

Analise URLs de requisições recebidas para extrair informações de roteamento:

// 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;

Exemplo: Construindo URLs dinamicamente

Construa URLs para chamadas de API e redirecionamentos:

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;

Exemplo: Manipulação de URLSearchParams

Trabalhe com parâmetros de query string de forma eficiente:

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;

Exemplo: Validação e normalização de URL

Valide e normalize URLs fornecidas pelo usuário:

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;

Exemplo: Roteamento de URL e correspondência de caminhos

Use análise de URL para roteamento de requisições:

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;

APIs com suporte

APIStatus
URL (global)🟢 Com suporte
URLSearchParams🟢 Com suporte
url.URL🟢 Com suporte
url.URLSearchParams🟢 Com suporte
url.format()🟢 Com suporte
url.parse()🟡 Depreciado (use new URL())
url.resolve()🟡 Depreciado (use new URL(relative, base))
url.domainToASCII()🟡 Parcialmente suportado
url.domainToUnicode()🟡 Parcialmente suportado
url.fileURLToPath()🟡 Parcialmente suportado
url.pathToFileURL()🟡 Parcialmente suportado
url.urlToHttpOptions()🟡 Parcialmente suportado

Recursos relacionados