Hone logo
Hone
Problems

Resolving Relative URLs with a Base URL

A common task in web development and API interactions is handling URLs. Often, you'll receive a relative URL (like /users or ../images/logo.png) and need to combine it with a base URL (like https://api.example.com/v1) to form a complete, absolute URL. This challenge focuses on implementing a robust URL resolution function in TypeScript.

Problem Description

Your task is to create a TypeScript function that takes a baseUrl and a relativeUrl as input and returns the resolved, absolute URL. This function should mimic the behavior of the browser's URL constructor when resolving relative URLs.

Key Requirements:

  • The function should correctly handle various combinations of base and relative URLs, including absolute paths, relative paths, and paths with query parameters or fragments.
  • It should gracefully handle scenarios where the baseUrl or relativeUrl might be malformed, although for this challenge, we can assume valid URL components for simplicity in most cases, focusing on the resolution logic.
  • The function should return a string representing the fully resolved URL.

Expected Behavior:

  • If relativeUrl is an absolute URL (starts with http://, https://, ftp://, etc.), it should be returned directly.
  • If relativeUrl is a path-only relative URL (e.g., /users, data/items), it should be appended to the baseUrl.
  • If relativeUrl starts with ../ or ./, it should be correctly resolved against the baseUrl's path.
  • Query parameters and fragments from the relativeUrl should be preserved and appended correctly.

Edge Cases to Consider:

  • What happens if the baseUrl ends with a / and the relativeUrl starts with a /?
  • What happens if the baseUrl does not end with a / and the relativeUrl does not start with a /?
  • How are ../ segments handled at the root of the baseUrl?
  • Handling of empty relativeUrl.

Examples

Example 1:

Input:
baseUrl: "https://api.example.com/v1/"
relativeUrl: "/users"

Output: "https://api.example.com/v1/users"
Explanation: The relative URL is a path that starts with a '/', so it's appended directly after the base URL's path.

Example 2:

Input:
baseUrl: "https://example.com/path/to/resource"
relativeUrl: "data"

Output: "https://example.com/path/to/data"
Explanation: The relative URL "data" is appended to the base URL's path, replacing the last segment.

Example 3:

Input:
baseUrl: "https://example.com/path/to/resource"
relativeUrl: "../another/path"

Output: "https://example.com/path/another/path"
Explanation: The "../" in the relative URL navigates up one directory level in the base URL's path.

Example 4:

Input:
baseUrl: "https://example.com/path?query=abc#fragment"
relativeUrl: "data?new_query=xyz"

Output: "https://example.com/path?new_query=xyz"
Explanation: The query parameters from the relative URL override those from the base URL. The fragment from the base URL is dropped.

Example 5:

Input:
baseUrl: "https://example.com/path/"
relativeUrl: "./sub/path"

Output: "https://example.com/path/sub/path"
Explanation: "./" indicates the current directory, so it's resolved to append "sub/path" to the base URL's path.

Example 6:

Input:
baseUrl: "https://example.com/"
relativeUrl: "/absolute/path"

Output: "https://example.com/absolute/path"
Explanation: Even though the baseUrl might imply a root, a relativeUrl starting with '/' will always resolve to the root of that base URL's origin.

Example 7:

Input:
baseUrl: "https://example.com/a/b/c"
relativeUrl: "../../d/e"

Output: "https://example.com/a/d/e"
Explanation: Two "../" segments navigate up two levels from "c" to "a", then "d/e" is appended.

Example 8:

Input:
baseUrl: "https://example.com"
relativeUrl: ""

Output: "https://example.com"
Explanation: An empty relative URL should resolve to the base URL itself.

Constraints

  • The baseUrl will be a valid URL string that includes a scheme (e.g., http, https).
  • The relativeUrl will be a string. It may be empty, an absolute URL, or a relative path.
  • Your function should return a string.
  • For this challenge, focus on the path and query/fragment resolution. Assume valid URL components (e.g., no invalid characters in paths unless part of a standard URL structure).

Notes

This challenge requires careful parsing and manipulation of URL components. Consider how you will:

  1. Separate the baseUrl into its constituent parts (scheme, host, path, query, fragment).
  2. Handle the different types of relativeUrl.
  3. Reconstruct the path correctly, accounting for . and .. segments.
  4. Combine the resolved path with the original baseUrl's scheme and host, and the appropriate query/fragment.

You might find it helpful to break down the problem into smaller, manageable steps. For instance, implement a helper function to normalize a path segment by segment.

Loading editor...
typescript