DEV Community

TheOnlyBeardedBeast
TheOnlyBeardedBeast

Posted on

 

Comparing URLs in Javascript

Why I need to compare URLs

There is an e-shop with a lot of filters, these filters can be saved by the user for notification purpose. The filters on the frontend are stored as a javascript object with a lot of nesting for different needs of the component, so comparing a database stored object with an actual filter object is possible, but we can do it differently. Actually every change in the filter affects the URL pathname and/or query string, this is done because we wanted to have shareable searches by the users.

It is not just comparing 2 strings

Actually it would be nice, but the query params can have a different order, and by changing the URL manually you can even create duplicates of the same property.

My solution

So first we transform 2 URL strings into URL objects.

const urls = [new URL(urlProp1),new URL(urlProp2)];
Enter fullscreen mode Exit fullscreen mode

Comparing the pathname is easy, there is no way to have it in bad order or to add not supported params to it, that's handled by our router, so comparing them is enough.

if(urls[0].pathname !== urls[1].pathname){
    return false;
}
Enter fullscreen mode Exit fullscreen mode

Next we exclude our URLSearchParams from our URL objects before we create our key-value objects.

const params = urls.map(url => url.searchParams);
Enter fullscreen mode Exit fullscreen mode

Before we create key-value objects from our URLSearchParams we quickly compare the length of our params. The object creation would eliminate duplicates in the URLSearchParams objects.

Actually you can skip this step. But it brings up uncertainty about duplicates, because duplacates can have different values with a same key.
(note: our e-shop eliminates duplicates on frontend and backend automatically)

if(params[0].toString().length !== params[1].toString().length){
    return false;
}
Enter fullscreen mode Exit fullscreen mode

So now we can create objects from our params. This step also eliminates duplicates, that is why we compared the length of our params above.

const paramObjects = params.map(param => {
    param.delete("page");

    return Object.fromEntries(param);

    // for nodejs where Object.fromEntries is not implemented
    // let paramObject = {};

    // for (let [key, value] of param.entries()) {
    //   paramObject[key] = value;
    // }

    // return paramObject;
});
Enter fullscreen mode Exit fullscreen mode

So at this point, we know that we have URLSearchParams with the same string length and without duplicate keys. So now we can compare the actual number of our params in our URLSearchParams.

if(Object.keys(paramObjects[0]).length !== Object.keys(paramObjects[1]).length){
    return false;
}
Enter fullscreen mode Exit fullscreen mode

Now we check if every key from one paramsObjects exists in the other and if every key have same value in both objects and we return the result from this check.

return Object.keys(paramObjects[0]).every(key => !!paramObjects[1][key] && paramObjects[1][key] === paramObjects[0][key]);

Enter fullscreen mode Exit fullscreen mode

So I ended up with this helper function.

const urlsEqual = (urlProp1,urlProp2) => {
  const urls = [new URL(urlProp1),new URL(urlProp2)];

  if(urls[0].pathname !== urls[1].pathname){
    return false;
  }

  const params = urls.map(url => url.searchParams);

  if(params[0].toString().length !== params[1].toString().length){
    return false;
  }

  const paramObjects = params.map(param => {
    param.delete("page");
    return Object.fromEntries(param);

    // for nodejs where Object.fromEntries is not implemented
    // let paramObject = {};

    // for (let [key, value] of param.entries()) {
    //   paramObject[key] = value;
    // }

    // return paramObject;
  });

  if(Object.keys(paramObjects[0]).length !== 
     Object.keys(paramObjects[1]).length){
       return false;
  }

  return Object.keys(paramObjects[0]).every(key => !!paramObjects[1][key] 
    && paramObjects[1][key] === paramObjects[0][key]);
}


Enter fullscreen mode Exit fullscreen mode

English isn’t my first language, so please excuse any mistakes.

PS: I know the host is not checked, implement it if you need it. Our client-server solution takes care of it.

Thank you all for your attention and time;

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.

The JavaScript Brief

1. Top 5 MERN STACK projects to improve your practical understanding

Boost your MERN Stack development skills by undertaking interesting beginner projects. These five engaging projects cover web applications and range from social media website applications to geo-social networking maps. Hone your understanding and apply modern techniques backed up by hands-on experience.

2. How To Optimize Your React App’s Performance

Learn the best optimizing techniques to make your React applications faster and more efficient. Focusing on the identification of performance bottlenecks and common pitfalls to avoid, these optimization strategies will keep your applications running smoothly even when faced with growing complexity.

3. A story of let, const, object mutation, and a bug in my code

In the pursuit of bug-free code, explore an incident involving a mix-up between const and let, making sure your custom code works effectively with third

party documentation. Discover best practices on program flow and learn about JavaScript's unpredictable aspects to ensure your core code is robust.