0

I want to find and validates dynamic path variable.

User can enter url and dynamic path variable in input box like below.

http://localhost:3000/{abc}
https://google.com/{a}/{bb}/{ccc}

Dynamic path variable is optional. Therefore url that does not have path variable is also fine.

However, if user wants to add dynamic path variable, it must start with '/{' and ends with '}'.

Therefore urls below are not valid.

https://google.com/{}
https://helloWorld/{aaa
http://localhost:3000/aaa}
http://localhost:9999/{aaa}}

Here is what I did.

first I split url using '/' and create a new array starts from 3rd index to the last index.

const url = 'https://google.com/{a}/{bb}/{ccc'

const splitUrl = url.split('/') // ['https:', '', 'google.com', '{a}', '{bb}', '{ccc']

const pathVaraibles = splitUrl.slice(3) // ['{a}', '{bb}', '{ccc']

Then I just need to check pathVariables array whether all elements in the array are valid variables.

Could this be the proper way to validate dynamic path variables in url?

GoonGamja
  • 1,936
  • 5
  • 20
  • 46
  • I think you can make use of [the URL API](https://developer.mozilla.org/en-US/docs/Web/API/URL). Example usage: `new URL('https://google.com/{a}/{bb}/{ccc') // { pathname: '/%7Ba%7D/%7Bbb%7D/%7Bccc', /* ... */ }`. – InSync May 08 '23 at 03:55

2 Answers2

1

You can try the following way:

function isValidUrlWithPathVariable(url) {
  const splitUrl = url.split('/');

  const pathVariables = splitUrl.slice(3).filter(i=>i);
  if (pathVariables.length === 0) {
    //URL does not have any path variables, which is valid
    return true;
  }
  const regex = /^{[^{}]+}$/;
  //check all the path variables against the regex
  for (let i = 0; i < pathVariables.length; i++) {
    if (!regex.test(pathVariables[i])) {
      return false;
    }
  }

  return true;
}


const urlValid1 = 'https://google.com';
const urlValid2 = 'http://localhost:3000/{aaa}';
console.log(isValidUrlWithPathVariable(urlValid1));  //true
console.log(isValidUrlWithPathVariable(urlValid2));  //true

const urlInvalid1 = 'https://google.com/{}';
const urlInvalid2 = 'https://helloWorld/{aaa';
const urlInvalid3 = 'http://localhost:3000/aaa}';
const urlInvalid4 = 'http://localhost:9999/{aaa}}';
console.log(isValidUrlWithPathVariable(urlInvalid1));//false
console.log(isValidUrlWithPathVariable(urlInvalid2));//false
console.log(isValidUrlWithPathVariable(urlInvalid3));//false
console.log(isValidUrlWithPathVariable(urlInvalid4));//false
Mamun
  • 66,969
  • 9
  • 47
  • 59
1

If any of these assumptions are incorrect, you'll have to adjust the final regular expressions. Everything depends a bit on what you're ultimately trying to do.

Are you trying to validate the URLs as well, or are we just assuming they're valid & only want to look at the dynamic component? If so, that's covered well in this SO question: What is the best regular expression to check if a string is a valid URL?.

Secondly, what if we have a URL of the form: https://website.com/User/{userid}/Profile: Is this a valid dynamic URL? I'm going to assume, "yes", but all examples "end with" the dynamic portion.

Thirdly, the dynamic strings you're using are of the form {aaa}, {abc}, etc. but you didn't really put any restrictions on them in the question. I'd assume "alphabetic" or "alphanumeric" but obviously other people have assumed they can be "anything that's not a curly brace" (i.e. [^{}]+ in a regex is "one or more elements + that aren't in the set [^] containing the values {}.")

Are you always using "fully qualified URLs" or can they also be "root relative"? E.g. https://localhost:3010/User/Profile/{userid} vs /User/Profile/{userid}. I'm assuming fully qualified, but there's benefits to using relative URLs in an app.


I'd definitely use a similar approach to @Mamun's answer and use a regular expression (regex) as well.

Leveraging the fact that, "...curly braces are unsafe characters, and are not valid in URIs..." I'd just:

  • Validate that the URL matches your expected form with a very basic check,
  • Use a slightly different regex to extract the path variables,
  • (Run whatever your code would be to dynamically replace those vars),
  • Run a final regex over the URL to determine it's valid (or just "use it" & trust nothing's gone awry).

// Starts with "http(s)://" then skips to the first "/"
// Checks it's either: /{<alphanumeric>} (e.g. /{abc})
// Or path component doesn't have `{}` in it at all (e.g. /Profile)
// * Repeat 0 or more times (e.g. http://a.com OR https://b.com/{a}/{b}/Test/{c}/)
function isDynamicUrl(url) {
    const testUrlRegex = /https*:\/\/[^/]+(\/({\w+})|([^{}]*))*?$/
    return testUrlRegex.test(url)
}

// Variables pulled from "somewhere"
const props = {
    userId: 5,
    area: "Designs",
}

const path = "https://example.com/{userId}/{area}/Index"
var url = ""

// matches will be of the form: [["/{userId}", "userId"], ["/{area}", "area"]]
if (isDynamicUrl(path)) {
    const replacementRegex = /\/{(\w+)}/g;
    url = path.replace(replacementRegex, (match, group1) => "/" + props[group1])
}

// url == "https://example.com/5/Designs/Index"
console.log(url)

For testing regular expressions, I'd recommend a site like https://regexr.com/ which freely lets you test an expression against a block of text to validate it. If you paste my expression into a site like that, it'll give a clearer explanation of how it works than I could probably describe.

You may need to make some small changes for testing there, e.g. I used multiple lines so I had to use the /gm flag (anchors like $ will respect newlines) & also account for \n (newline) when testing: /(https*://[^/\n])(/([^{}\n])|({\w+}))*?$/gm

Lovethenakedgun
  • 731
  • 6
  • 22
  • before the pathname validation, url validation is proceeded whether the url is "fully qualified URLs" or not and yes url such as 'https://website.com/User/{userid}/Profile' is also valid. There is also rule that must be applied to dynamic string. It allows only english and _ in terms of naming. – GoonGamja May 09 '23 at 01:12
  • 1
    I used `\w+` in my example, which matches one or more "word characters" (alphanumeric ASCII & underscore). If you want to exclude digits you'd use something like `[A-Za-z_]+` which is explicitly capital & lower-case ASCII letters & underscore. Though both would exclude diacritics / accented characters, which can show up in loanwords (e.g. entrée). – Lovethenakedgun May 09 '23 at 06:40