Urigo / graphql-scalars

A library of custom GraphQL Scalars for creating precise type-safe GraphQL schemas.
https://www.the-guild.dev/graphql/scalars
MIT License
1.87k stars 133 forks source link

Scalar `URL` adds trailing slashes to URLs #2325

Open jaydenseric opened 5 months ago

jaydenseric commented 5 months ago

Issue workflow progress

Progress of the issue based on the Contributor Workflow


Describe the bug

The scalar URL adds a trailing slash to URLs, which is undesirable as it modifies the input URL string. The reason this happens is because it uses the native URL class, which "normalizes" the URL string:

// Outputs https://test.test/
new URL("https://test.test").href;

https://github.com/Urigo/graphql-scalars/blob/3182ad51178f2306f120c844deb2de7eae03e3ba/src/scalars/URL.ts#L18

It is undesirable for URL "normalization" to occur. Some servers respond with different content depending if there is a trailing slash or not. For example, these URLs have different redirects/responses:

In our API, we have situations where we want the URL to be preserved exactly as it is input/stored, as the purpose of the API is to test what certain URLs respond with. A customer might want to separately test the difference between their website rendering a route with a slash and without, but if the scalar URL normalizes both URL strings to the same string with a trailing slash then they can't do that.

To Reproduce Steps to reproduce the behavior:

Try resolving the value https://test.test with a field with the scalar URL, and see that the value in the resolved data becomes https://test.test/.

Expected behavior

The scalar URL should validate the URL string, but not "normalize" the string if it's a valid URL.

Environment:

Additional context

As a side note, there are opportunities to optimize this scalar URL implementation. It would be good that if it receives a value that is already a URL instance, it uses that instead of inefficiently converting it to a string and then back again into another URL instance:

https://github.com/Urigo/graphql-scalars/blob/3182ad51178f2306f120c844deb2de7eae03e3ba/src/scalars/URL.ts#L18

Also when serializing, if it's already a URL instance it should just serialize that instance via .href instead of converting to a string then back into a URL instance, then back into a string again:

https://github.com/Urigo/graphql-scalars/blob/3182ad51178f2306f120c844deb2de7eae03e3ba/src/scalars/URL.ts#L10-L16

Furthermore, the URL instance method .toString() shouldn't be used when .href can be used to the same effect with less code.