Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

URL with relative uri #9

Open
XadillaX opened this issue Jun 30, 2022 · 13 comments
Open

URL with relative uri #9

XadillaX opened this issue Jun 30, 2022 · 13 comments
Assignees

Comments

@XadillaX
Copy link

E.g. fetch('/foo'), what should the whole URL should be?

@lucacasonato
Copy link
Member

We need documentation for what is done by:

  • Deno
  • Undici
  • CFW
  • Browsers (main thread)
  • Browsers (workers)
  • Browsers (service workers)

@jimmywarting
Copy link

If i could go back and change how node-fetch was first written then i would have made it into a class that you have to construct with some options...

const fetch = new Fetch({
  base: 'http://localhost:8080',
  userAgent,
  cacheStorage,
  ...etc
})

fetch('/foo') // http://localhost:8080/foo

@XadillaX
Copy link
Author

Maybe we can define the location not only HTTP or file protocol, but use something like winter:// or something else.

@KhafraDev
Copy link

undici will throw an error on relative urls. Browser side it makes sense, but I don't personally think it's a good idea elsewhere.

@XadillaX
Copy link
Author

undici will throw an error on relative urls. Browser side it makes sense, but I don't personally think it's a good idea elsewhere.

Think of one situation of Winter's SSR:

If the frontend code like this: (and if the JavaScript is http://foo/index.js)

fetch('/api');

it means to fetch the data from http://foo/api. If Winter support this directly, the frontend JavaScript needn't do any modification when it runs on Winter's SSR. But if it throws error, the developer may have to modify this frontend JavaScript code to adapt Winter's SSR.

@KhafraDev
Copy link

In the front end, that behavior makes sense because browsers have a concept of origin/location. The spec uses an "API base URL" to parse relative urls. This is easy (enough) to understand when your environment has an origin.

On the server side, even if this was implemented, the behavior would not be transparent, and would cause confusion among users. What would the base URL be? Would users understand this behavior?

Where do you believe both of these requests should fetch in node/deno, for example? I commented where the browser will try to fetch if done from this page.

fetch('a') // https://github.com/wintercg/fetch/issues/a
fetch('/a') // https://github.com/a

Regardless of the outcome, server environments will need to deviate from the spec. Origins are supposed to be "... generally immutable. Only the domain of a tuple origin can be changed, and only through the document.domain API."

If having a way to change the origin deviates from the spec, and not having a way to change an origin deviates from the spec, is it worth having? Node doesn't have a concept of origin and for a good reason; it can't mimic the behavior in a way that is clear to the user and follows the spec's model.

@blittle
Copy link

blittle commented Jul 21, 2022

I plan on documented how all of the platforms behave, but Deno for example, provides a flag for running a script to define the location and subsequently origin. Doing so allows them to handle relative paths. If --location is not provided, it throws:

image

@benjamingr
Copy link
Member

@jimmywarting this is the API Node.js core wanted to do initially when we were talking about fetch in 2018 but it's not the API users have been asking for.

@jimmywarting
Copy link

yea... i know, ppl want something close to the spec as possible....
there could exist an existing (default) globalThis.fetch that dose not handle relative urls and also a globalThis.Fetch constructor 🤷‍♂️

didn't actually follow that discussion in 2018...
would it be possible to actually have an origin (even if it dose not make sense in the backend?

Kinda like: node --origin=localhost:8080
Maybe could be possible to define it inside of package.json too { "origin": "localhost:8080" }?

but perhaps somebody want something more dynamic and programmable and not so static.


Something far fetch and possible way for something to actually have an origin would be if someone where to do a http import:

#!/usr/bin/node

import mod from 'https://example.com/module.js'
import github from 'https://github.com/api.js'

then mod would have a import.meta.url equal to: https://example.com/module.js
and github would have import.meta.url equal to: https://github.com/api.js

if github.com/api.js would call fetch('/users') then it could resolve the origin relative to import.meta.url

console.assert(import.meta.url === 'https://github.com/api.js')
fetch('/users')  // would fetch https://github.com/users (based on import.meta.url)
console.assert(import.meta.url === 'https://example.com/module.js')
fetch('/weather')  // would fetch https://example.com/weather (based on import.meta.url)

I have no idea if it would be even at all possible for fetch to resolve something based on import.meta.url, we would have to use stack traces to figure out what file/origin called what...

it would certainly be abnormal and not according to spec... and also possible breaking in some cases.
it could certainly be a grate feature but it's not so backward compatible friendly solution either.

maybe something that would be best would be to have an origin on the Agent instead

@blittle
Copy link

blittle commented Jul 25, 2022

@jimmywarting I think that having each dependency resolve a different base URL would be confusing, and differ vastly from what happens in the browser. The base URL of fetch is defined by the base document, not the module dependencies. IMO it would be best to be able to also universally define a base URL, regardless of where the modules are loaded.

@benjamingr
Copy link
Member

yea... i know, ppl want something close to the spec as possible....

No... honestly people didn't care a lot about it being spec compliant that was mostly driven by core members caring. People just didn't want the extra makeFetch step and wanted a single function.


The "based on module URL if any" suggestion is interesting but I agree it diverges much from what browsers do and I'd rather have no supported behavior than different supported behavior here for server runtimes, probably.

@Ethan-Arrowood
Copy link
Collaborator

honestly people didn't care a lot about it being spec compliant that was mostly driven by core members caring.

fwiw we cared about spec compliance because of what we would hear from community. in my experience, its a double edged sword. When we build something spec compliant, users that expect a fetch-like client will complain the loudest. When we build something that is fetch-like, users that expect a compliant client will complain the loudest. We can't really win one way or another (but that is where WinterCG Fetch will change things. we can be fetch-like and spec compliant at the same time!).

So for the purposes of this issue we should remember we are building for runtimes / server environments here.

@KhafraDev
Copy link

undici supports fetching relative urls now, albeit in a kinda contrived way -

import { setGlobalOrigin, fetch } from 'undici'

setGlobalOrigin('http://localhost:3000')

const response = await fetch('/api/ping')

console.log(response.url) // http://localhost:3000/api/ping

@Ethan-Arrowood Ethan-Arrowood transferred this issue from another repository Jan 19, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants