简体   繁体   中英

URL Parse Exercise (JavaScript)

So here is a description of the problem that I've been talked to solve:

We need some logic that extracts the variable parts of a url into a hash. The keys of the extract hash will be the "names" of the variable parts of a url, and the values of the hash will be the values. We will be supplied with:

  1. A url format string , which describes the format of a url. A url format string can contain constant parts and variable parts, in any order, where "parts" of a url are separated with "/". All variable parts begin with a colon. Here is an example of such a url format string:
 '/:version/api/:collection/:id'
  1. A particular url instance that is guaranteed to have the format given by the url format string. It may also contain url parameters. For example, given the example url format string above, the url instance might be:
'/6/api/listings/3?sort=desc&limit=10'

Given this example url format string and url instance, the hash we want that maps all the variable parts of the url instance to their values would look like this:

{
 version: 6,
 collection: 'listings',
 id: 3,
 sort: 'desc',
 limit: 10
}

So I technically have a semi-working solution to this but, my questions are:

  1. Am I understanding the task correctly? I'm not sure if I'm supposed to be dealing with two inputs (URL format string and URL instance) or if I'm just supposed to be working with one URL as a whole. (my solution takes two separate inputs)

  2. In my solution, I keep reusing the split() method to chunk the array/s down and it feels a little repetitive. Is there a better way to do this?

If anyone can help me understand this challenge better and/or help me clean up my solution, it would be greatly appreciated!

Here is my JS:

 const obj = {}; function parseUrl(str1, str2) { const keyArr = []; const valArr = []; const splitStr1 = str1.split("/"); const splitStr2 = str2.split("?"); let val1 = splitStr2[0].split("/"); let val2 = splitStr2[1].split("&"); splitStr1.forEach((i) => { keyArr.push(i); }); val1.forEach((i) => { valArr.push(i); }); val2.forEach((i) => { keyArr.push(i.split("=")[0]); valArr.push(i.split("=")[1]); }); for (let i = 0; i < keyArr.length; i++) { if (keyArr[i];== "" && valArr[i];== "") { obj[keyArr[i]] = valArr[i]; } } return obj. }: console:log(parseUrl('/:version/api/,collection/?id'; '/6/api/listings/3?sort=desc&limit=10'));

And here is a link to my codepen so you can see my output in the console: https://codepen.io/TOOTCODER/pen/yLabpBo?editors=0012

Am I understanding the task correctly? I'm not sure if I'm supposed to be dealing with two inputs (URL format string and URL instance) or if I'm just supposed to be working with one URL as a whole. (my solution takes two separate inputs)

Yes, your understanding of the problem seems correct to me. What this task seems to be asking you to do is implement a route parameter and a query string parser. These often come up when you want to extract data from part of the URL on the server-side (although you don't usually need to implement this logic your self). Do keep in mind though, you only want to get the path parameters if they have a : in front of them (currently you're retrieving all values for all), not all parameters (eg: api in your answer should be excluded from the object (ie: hash)).

In my solution, I keep reusing the split() method to chunk the array/s down and it feels a little repetitive. Is there a better way to do this?

The number of .split() methods that you have may seem like a lot, but each of them is serving its own purpose of extracting the data required. You can, however, change your code to make use of other array methods such as .map() , .filter() etc. to cut your code down a little. The below code also considers the case when no query string (ie: ?key=value ) is provided:

 function parseQuery(queryString) { return queryString.split("&").map(qParam => qParam.split("=")); } function parseUrl(str1, str2) { const keys = str1.split("/").map((key, idx) => [key.replace(":", ""), idx, key.charAt(0) === ":"]).filter(([,,keep]) => keep); const [path, query = ""] = str2.split("?"); const pathParts = path.split("/"); const entries = keys.map(([key, idx]) => [key, pathParts[idx]]); return Object.fromEntries(query? [...entries, ...parseQuery(query)]: entries); } console.log(parseUrl('/:version/api/:collection/:id', '/6/api/listings/3?sort=desc&limit=10'));

It would be even better if you don't have to re-invent the wheel, and instead make use of the URL constructor , which will allow you to extract the required information from your URLs more easily, such as the search parameters , this, however, requires that both strings are valid URLs :

 function parseUrl(str1, str2) { const {pathname, searchParams} = new URL(str2); const keys = new URL(str1).pathname.split("/").map((key, idx) => [key.replace(":", ""), idx, key.startsWith(":")]).filter(([,,keep]) => keep); const pathParts = pathname.split("/"); const entries = keys.map(([key, idx]) => [key, pathParts[idx]]); return Object.fromEntries([...entries, ...searchParams]); } console.log(parseUrl('https://www.example.com/:version/api/:collection/:id', 'https://www.example.com/6/api/listings/3?sort=desc&limit=10'));

Above, we still need to write our own custom logic to obtain the URL parameters, however, we don't need to write any logic to extract the query string data as this is done for us by using URLSearchParams. We're also able to lower the number of .split() s used as we can obtain use the URL constructor to give us an object with a parsed URL already. If you end up using a library (such as express ), you will get the above functionality out-of-the-box.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM