1

I'm building an app on NodeJS that uses Figma API, and I need to check if the string passed by a user is a valid Figma link. I'm currently using this simple regex expression to check the string:

/^https\:\/\/www.figma.com\/.*/i

However, it matches all links from figma.com, even the home page, not only links to the files and prototypes. Here is an example Figma link that should match:

https://www.figma.com/file/OoYmkiTlusAzIjYwAgSbv8wy/Test-File?node-id=0%3A1

Also the match should be positive if this is a prototype link, with proto instead of file in the path.

Moreover, since I'm using the Figma API, it would be useful to extract necessary parts of the URL such as the file ID and node ID at the same time.

Gleb Sabirzyanov
  • 765
  • 1
  • 8
  • 18

1 Answers1

1

TL;DR

✅ Use this expression to capture four most important groups (type, file id, file name and URL properties) and work from there.

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/?([^\?]+)?(.*))?$/

From the docs

This is the regex expression code provided by Figma on their developer documentation page about embeds:

/https://([w.-]+.)?figma.com/(file|proto)/([0-9a-zA-Z]{22,128})(?:/.*)?$/

However, it doesn't work in JS as the documentation is currently wrong and this expression has multiple issues:

  • Slashes and a dots are not escaped with backslashes.

  • It doesn't match from the start of the string. I added the start of string anchor ^ after VLAZ pointed it out in the comments. This way we will avoid matching strings that don't start with https, for example malicious.site/?link=https://figma.com/...

  • It will match not only www. subdomain but any other amount of W which is not great (e.g. wwwww.) — it can be fixed by replacing letter match with a simpler expression. Also this is a useless capturing group, I'll make it non-capturing.

  • It would be nice if the link matched even if it doesn't begin with https:// as some engines (e.g. Twitter) strip this part for brevity and if person is copying a link from there, it should still be valid.

After applying all the improvements, we are left with the following expression:

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/

There is also a dedicated NPM package that simply checks the URL against the similar pattern. However, it contains some of the flaws listed above so I don't advice using it, especially for just one line of code.


Extracting parts of the URL

This expression is extremely useful to use with Figma API as it even extracts necessary parts from the URL such as type of link (proto/file) and the file key. You can access them by indexes.

You can also add a piece of regex to match specific keys in the query such as node-id:

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?node-id=([^&]*)$/

Now you can use it in code and get all the parts of the URL separately:

var pattern = /^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?node-id=([^&]*)$/

var matched = 'https://www.figma.com/file/OoYmkiTlusAzIjYwAgSbv8wy/Test-File?node-id=0%3A1'.match(pattern)

console.log('url:', matched[0]) // whole matched string
console.log('type:', matched[1]) // group 1
console.log('file key:', matched[2]) // group 2
console.log('node id:', matched[3]) // group 3

Digging deeper

I spent some time recreating this expression almost from scratch so it would match as many possible Figma file/prototype URLs without breaking things. Here are three similar versions of it that would work for different cases.

✅ This version captures the URL parameters and the name of the file separately for easier processing. You can check it here. I added it in the beginning of the answer, because I think it's the cleanest and most useful solution.

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/?([^\?]+)?(.*))?$/

The groups in it are as following:

  • Group 1: file/proto
  • Group 2: file key/id
  • Group 3: file name (optional)
  • Group 4: url parameters (optional)

✅ Next up, I wanted to do the same but separating the /duplicate part that can be added in the end of any Figma URL to create a duplicate of the file upon opening.

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/?([^\?]+)?([^\/]*)(\/duplicate)?)?$/

✅ And back to the node-id parameter. The following regex expression finds and captures multiple URLs inside a multiline string successfully. The only downside that I found in the end is that it (as well as all the previous ones) doesn't check if this URL contains unencoded special characters meaning that it can potentially break things, but it can be avoided by manually encoding all parameters using encodeURI() function.

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/([^\?\n\r\/]+)?((?:\?[^\/]*?node-id=([^&\n\r\/]+))?[^\/]*?)(\/duplicate)?)?$/gm

There are six groups that can be captured by this expression:

  • Group 1: file/proto
  • Group 2: file key/id
  • Group 3: file name (optional)
  • Group 4: url parameters (optional)
    • Group 5: node-id (optional; only present when group 4 is present)
  • Group 6: /duplicate

And, finally, here is the example of a match and its groups (or try it yourself):

groups examples

Gleb Sabirzyanov
  • 765
  • 1
  • 8
  • 18
  • 1
    "*However, it doesn't work in JS as slashes and a dot should be escaped with backslashes, leaving us with the following expression:*" but the slashes part is true for anything that uses `/` as a regex delimiter. As for `.` all regex engines would interpret it as "any character" when used outside of a character class. This is not JS specific - the documentation is simply wrong. I also notice it has a `$` anchor but no `^` anchor, which seems odd. – VLAZ Mar 30 '19 at 07:03
  • Thanks for telling me about that, I'm not a pro at regex. I'll tell the Figma team to correct the documentation! About the `^` anchor, you are right, I didn't notice it wasn't there. I will improve the answer. – Gleb Sabirzyanov Mar 31 '19 at 11:26
  • I think `[w.-]+` should be `[\w.-]+` – Toto Mar 31 '19 at 15:00
  • @Toto good point! Will it match any `figma.com` subdomain then? At the moment it only checks for `www.` because currently Figma doesn't use any other subdomains for files and prototypes links. But as I'm experimenting with this more, I think it would be better to simply use `(www.)` in that capturing group because currently it will match `wwwww.` which is not something we want. – Gleb Sabirzyanov Apr 01 '19 at 00:07
  • Sorry, I meant `(www\.)`. – Gleb Sabirzyanov Apr 01 '19 at 00:22
  • @VLAZ I updated the answer with new expressions, I would be glad if you take a look. The initial solution I came up with was matching some false links. Now it seems to be bulletproof, I tested it as much as I could! ✨ – Gleb Sabirzyanov Apr 01 '19 at 11:02