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
baseUrlorrelativeUrlmight 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
relativeUrlis an absolute URL (starts withhttp://,https://,ftp://, etc.), it should be returned directly. - If
relativeUrlis a path-only relative URL (e.g.,/users,data/items), it should be appended to thebaseUrl. - If
relativeUrlstarts with../or./, it should be correctly resolved against thebaseUrl's path. - Query parameters and fragments from the
relativeUrlshould be preserved and appended correctly.
Edge Cases to Consider:
- What happens if the
baseUrlends with a/and therelativeUrlstarts with a/? - What happens if the
baseUrldoes not end with a/and therelativeUrldoes not start with a/? - How are
../segments handled at the root of thebaseUrl? - 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
baseUrlwill be a valid URL string that includes a scheme (e.g.,http,https). - The
relativeUrlwill 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:
- Separate the
baseUrlinto its constituent parts (scheme, host, path, query, fragment). - Handle the different types of
relativeUrl. - Reconstruct the path correctly, accounting for
.and..segments. - 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.