Search code examples
regexmockingwiremockwiremock-standalone

WireMock not matching regex with negative lookahead


I'm currently facing an issue when trying to get my standalone WireMock to match a GET request with a certain path pattern using a regex with a negative lookahead:

{
    "request": {
      "method": "GET",
      "urlPathPattern": "\/my\/interesting\/path\/(\\?![0-9]*$)(\b[0-9A-Z]{11}\b)"
    },
    "response": {
      "status": 200,
      "body": "",
      "headers": {
        "Content-Type": "application/json"
      }
    }
  }

When checking the WireMock logs, a near miss is logged. As suggested by WireMock, I escaped the question mark operator within my regex with a double backslash. Though, this did not help either.

I expect the url path pattern to match urls that ends with an alphanumeric, eleven character uppercase string, such as:

http://myapp:8080/my/interesting/path/ABCDEF12345

I've already checked if my regex is valid and matches the cases that I would expect it to, which it does.

What might be of use: I'm using WireMock version 2.33.2 (docker image wiremock/wiremock:2.33.2)


Solution

  • If I understand you right, you need to match an 11-character string at the end, that consists of uppercase letters and digits only but does not consist of digits only, right? If WireMock's regex engine does not support negative lookahead - and that's what it looks like, if it doesn't match your regex but isn’t all that surprising neither, since there are quite a view regex implementations that do not support look-aheads), you have two choices.

    1. You can create 11 different possible endings and put them together with | looking for a letter at each of the 11 positions like this:

    /my/interesting/path/([A-Z][A-Z0-9]{10}|[A-Z0-9][A-Z][A-Z0-9]{9}|[A-Z0-9]{2}[A-Z][A-Z0-9]{8}|[A-Z0-9]{3}[A-Z][A-Z0-9]{7}|[A-Z0-9]{4}[A-Z][A-Z0-9]{6}|[A-Z0-9]{5}[A-Z][A-Z0-9]{5}|[A-Z0-9]{6}[A-Z][A-Z0-9]{4}|[A-Z0-9]{7}[A-Z][A-Z0-9]{3}|[A-Z0-9]{8}[A-Z][A-Z0-9]{2}|[A-Z0-9]{9}[A-Z][A-Z0-9]|[A-Z0-9]{10}[A-Z])$

    or

    1. You use priorities and define three matches (taking your comment of not allowing 11 digits to match a digit-only ending into account) like this:
    {
        "priority": 1,
        "request": {
          "method": "GET",
          "urlPathPattern": "/my/interesting/path/[0-9]{11}$"
        },
        "response": {
          "status": 404,
          "body": "",
          "headers": {}
        }
      }
    

    and

    {
        "priority": 2,
        "request": {
          "method": "GET",
          "urlPathPattern": "/my/interesting/path/[0-9]*$"
        },
        "response": {
          "status": 200,
          "body": "whatever is necessary for the digits-only or empty url",
          "headers": {
            "Content-Type": "application/json"
          }
        }
      }
    

    and

    {
        "priority": 3,
        "request": {
          "method": "GET",
          "urlPathPattern": "/my/interesting/path/[0-9A-Z]{11}$"
        },
        "response": {
          "status": 200,
          "body": "",
          "headers": {
            "Content-Type": "application/json"
          }
        }
      }
    

    The first match (priority 1) will pick up any URL that ends in 11 digits so that the second one is never tried for 11 digits. The third match (priority 3) will then only be tried, if the first one (priority 1) and second one (priority 2) did not match, thus guaranteeing there are not just digits if the third one matches.

    The priority field is documented in the 'stubbing' part of the WireMock documentation: https://wiremock.org/docs/stubbing/

    Hope that get's you going...