colinhacks / zod

TypeScript-first schema validation with static type inference
https://zod.dev
MIT License
34.03k stars 1.19k forks source link

`z.string().url()` claims invalid URL when `URL` is not in the global scope #2395

Open Jackman3005 opened 1 year ago

Jackman3005 commented 1 year ago

Hello and thanks to everyone working on Zod, it's an amazing library!

Scenario

I have code running on a bare-bones v8 engine and there is not access to many of the standard Javascript APIs by default, including URL which is common in most environments.

Issue

Zod works well in this bare-bones environment for most things, but I recently got quite hung up on why all URLs were invalid. After digging I realized Zod validates strings as valid URLs through use of the URL web standards API.

The error I was receiving when URL was not on global scope was:

{
  "issues": [
    {
      "validation": "url",
      "code": "invalid_string",
      "message": "Invalid url",
      "path": [
        "components",
        0,
        "url"
      ]
    }
  ],
  "name": "ZodError"
}

However, when I use URL in the environment outside of Zod I get the following:

Uncaught ReferenceError: URL is not defined

Next steps

1) I think it's fine that Zod marks the URL as invalid, but I think there needs to be some way to be informed that the API Zod is using for validation is not actually available in this environment and all strings will be invalid URLs even when they are valid.

2) This creates a followup question which is: What other standard APIs does Zod depend on that may be absent or behave different based on execution environment?

Cheers and thanks for reading this far! Jack

Jackman3005 commented 1 year ago

For anyone else who lands here with a similar issue I was able to get around the problem by using the core-js URL poly/pony-fills

My particular environment required me to import the ponyfill and set it on globalThis like so (yarn add core-js-pure):

// eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-assignment
const urlPonyfill = require("core-js-pure/actual/url");

if (!Object.getOwnPropertyNames(globalThis).includes("URL")) {
  Object.defineProperty(globalThis, "URL", {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
    value: urlPonyfill,
  });
}

But I expect most people would be able to just do (yarn add core-js):

import "core-js/actual/url"
stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Jackman3005 commented 1 year ago

Would still be great to improve the error message on this.

jdelauney commented 6 months ago

URL validation is clearly not precise enough For example : http:www.acme.com is valid http:www is valid www.acme.com is not valid etc...

a basic and enought regEx could be something like that : /((?:(https|http)\:\/\/)|(?:www\.))([a-zA-Z0-9]{3,192})((\.[a-zA-Z]{2,3}))?(?:(\.[a-zA-Z]{2,3}))$/gi

ps: Is protected against RedOs attack

Valid :
www.demo.com
http://foo.co.uk
https://demo.com

Invalid :
http://127.0.0.1
http://127.0.0.1/something
demo.com
https://localhost:3000/test
httpabrakadabra.co//
http:google.com
http://no-tld-here-folks
http://potato.54.211.192.240/
felipetavora commented 1 month ago

My case the same error was solved with a spaces in my variables. I didn't see spaces and i fixed removing all spaces from my .env file.

old .env file:

DATABASE_URL = "postgresql://docker:docker@localhost:5432/inorbit"

fixed .env file: DATABASE_URL="postgresql://docker:docker@localhost:5432/inorbit" (WITHOUT SPACES)

i hope helped :D thx