8

I am getting warnings in VS Code that url.format from the NodeJS URL module is deprecated.

const nodeUrl = require('url')

const url = nodeUrl.format({
  protocol: 'https',
  host: 'example.com',
  pathname: 'somepath'
})

What shall I use instead? Is it fully safe to just replace the above by

const buildUrl = (url) => url.protocol + '://' + url.host + '/' + url.pathname

Are these two functions equivalent, that is, for any object input with that structure, it results in the same output? Doesn't url.format have any magic that I may miss? For example pathname with or without leading /.

My project is huge with a lot of calls to url.format and I want to be sure that nothing breaks.

edit: Apparently we should use WHATWG URL standard

Is then this the correct replacement?

const buildUrl = (url) => new URL(url.pathname, url.protocol + '://' + url.host)
8
  • If you go through to the types that the warning is derived from, the deprecation tells you what to use too - the form that takes a URL not a vanilla object. Commented Dec 12, 2021 at 20:29
  • @user2864740 my messy search is not very effective, could you point me where that documentations is? Commented Dec 12, 2021 at 20:29
  • @jonrsharpe what is a WHATWG URL API? Commented Dec 12, 2021 at 20:30
  • 2
    To clarify the comment above, what you've linked to in the docs is not the deprecated form, which is why it doesn't suggest what to use instead. nodejs.org/api/url.html#urlformaturlobject is what you're calling, nodejs.org/api/url.html#urlformaturl-options is what you should be. Commented Dec 12, 2021 at 20:34
  • 1
    @jonrsharpe thanks a lot, but it's still not clear for me how should I replace that url.format(urlObject) using the WHATWG API? Just new URL(urlObject.pathname, urlObject.protocol + '://' + urlObject.host)? Commented Dec 12, 2021 at 20:42

2 Answers 2

2

Take a look at the documentation for URL, and be sure to note the differences in certain properties like host (includes port) vs hostname (doesn't). Based on the components in your question, it seems like you need to use a function like the following, which you can extend for your needs:

function urlFromComponents ({pathname = '/', protocol = 'https:', ...props} = {}) {
  const url = new URL('https://site.example');
  url.protocol = protocol;
  url.hostname = props.hostname;
  url.pathname = pathname;
  return url;
}

const protocol = 'https';
const hostname = 'example.com';
const pathname = 'somepath';

const url1 = urlFromComponents({
  hostname,
  pathname, // pathname will have "/" prepended if absent
  protocol, // protocol actually ends in ":", but this will also be fixed for you
});

const url2 = urlFromComponents({hostname, pathname});

console.log({url1, url2});

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot, but check my answer, is more general :)
0

Node refers that the url.format method taking as input an urlObject is deprecated, although it is still a stable solution

enter image description here

We should now use the WHATWG URL API. Note that the url module fetched with require('url') provides two APIs for working with URLs: a legacy API that is Node.js specific, and a newer API that implements the same WHATWG URL Standard used by web browsers.

A one-liner solution that tries to emulate the legacy url.format method API with the new WHATWG URL Standard constructor may be

const urlFrom = (urlObject) => String(Object.assign(new URL("http://a.com"), urlObject))

Test it here

const urlFrom = (urlObject) => String(Object.assign(new URL("http://a.com"), urlObject))

const url1 = urlFrom({
  protocol: 'https',
  hostname: 'example.com',
  pathname: 'somepath'
})
console.log('url1:', url1) // https://example.com/somepath

const url2 = urlFrom({
  protocol: 'https:',
  host: 'example.com',
  pathname: '/somepath'
})
console.log('url2:', url2) // https://example.com/somepath

const url3 = urlFrom({
  protocol: 'https:',
  host: 'example.com:8080',
  pathname: '/somepath'
})
console.log('url3:', url3) // https://example.com:8080/somepath

const url4 = urlFrom({
    protocol: 'http:',
    hostname: 'example.com',
    port: 8080,
    pathname: '/somepath'
  })
console.log('url4:', url4) // http://example.com:8080/somepath

const url5 = urlFrom({
    protocol: 'https:',
    hostname: 'example.com',
    port: 8080,
    pathname: '/somepath',
    username: 'john',
    password: 'abc',
    search: 'item=bike'
  })
console.log('url5:', url5) // https://john:[email protected]:8080/somepath?item=bike

2 Comments

The problem with that solution is that it doesn't support query params:/
I think this is the right solution. Query params are in the pathname key so it's ok. What I do not like is the new URL(someString) instance, but I do not find another way to do it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.