2

I'm trying to stub a RESTful API. One of the resources return the details when the resource is (indeed) found, or an HTTP 404 (Not Found) when, eventually, there is no resource for the given URL.

This is my simplified stub/mapping:

{
  "mappings": [
    {
      "name": "Retrieve Items",
      "request": {
        "headers": {
          "accept": {
            "caseInsensitive": true,
            "equalTo": "application/json"
          }
        },
        "method": "GET",
        "urlPathPattern": "/api/items/[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"
      },
      "response": {
        "bodyFileName": "items-api/responses/retrieve/{{ request.pathSegments.[2] }}.json",
        "headers": {
          "content-type": "application/json"
        },
        "status": 200
      }
    }
  ]
}

Then I have several JSON files (in /home/wiremock/__files/items-api/responses/retrieve/ to match the requests against — but I can't find a way to implement the HTTP 404 (Not Found) scenario:

{
  "timestamp": {{ now }},
  "status": 404,
  "error": "Not Found",
  "message": null,
  "path": "{{ request.path }}"
}

With this config I get back (the expected, but not useful for my use case) response from WireMock that the file name uuid-sent-in-request.json is not found.

Is there a way to implement this behavior currently?

x80486
  • 6,627
  • 5
  • 52
  • 111
  • Are you asking for a way to return the 404 only when your specific JSON file isn't found? I was a little confused about what your exact ask is. – agoff Sep 20 '21 at 14:05
  • I said _an HTTP `404` (`Not Found`) when, eventually, there is no resource for the given URL_. Basically, I'm stubbing certain resources that I know they exist, and for anything else, it would be an HTTP `404`. That's how the current RESTful API works also. I want to be able to mimic what the RESTful API offers: if you hit `/api/resource/{id}` and that's stubbed (read: exists), return the data, otherwise return a specific `404` response based on the aforementioned template. – x80486 Sep 20 '21 at 14:15
  • 1
    But that 404 response is dependent on if the JSON file does not exist in the `__files/` directory, correct? – agoff Sep 20 '21 at 14:19
  • Indeed; in the way this is implemented, it would be, for that resource in particular, if a given JSON file is not found, it would mean that it should return an HTTP `404` with the template I want. – x80486 Sep 20 '21 at 14:23
  • I'm guessing that the list of JSON files in that directory will fluctuate and/or is large enough to justify not having specific matches for the JSON files, and a catch-all match for any JSON files that do not exist? (Trying to get a little more information before I brainstorm an idea) – agoff Sep 20 '21 at 14:36
  • I just have `4` or `5` files there, one for each test case. It's not a huge list. I would avoid a specific match for the HTTP `404` response, but if that's the only way to implement it, I guess I would have to go that route. – x80486 Sep 20 '21 at 21:56

2 Answers2

1

Currently you would need to write a ResponseDefinitionTransformer to get the behaviour you're looking for.

It would need to check whether the ResponseDefinition passed in the parameter required a file, then if so check whether the file exists by doing something like:

try {
    fileSource.getBinaryFileNamed(bodyFileName).readContents();
} catch (FileNotFoundException e) {
    return WireMock.notFound().withBody("custom body");
}

// Otherwise return the unmodified response definition
Tom
  • 3,471
  • 21
  • 14
  • But this is something that it would be impossible to do if I'm using WireMock in a Docker container, and writing the stubs in JSON files, right? I have no way to write anything in Java at that point. I was actually looking for some way to execute a `when` clause in the DSL, and that would rule what use case will match first. – x80486 Sep 21 '21 at 13:18
  • 2
    You can build your transformer into a JAR and include it when running Docker: https://github.com/rodolpheche/wiremock-docker#use-wiremock-extensions – Tom Sep 21 '21 at 13:32
1

Tom's answer will work as well. I think the benefits to his solution are that they aren't tied to specific request URLs, but my suggestion is to have a specific mapping for the files that will match with their specific JSON files, and a catch-all mapping for un-matched files. By assigning the requests with JSON responses a higher priority, WireMock will check those first, and if the request does not match any of the values specified in that mapping, will then go on to check if the second mapping matches, and return a 404.

{
  "mappings": [
    {
      "name": "Retrieve Items - Success",
      "priority": 1, // arbitrary number lower than the second priority
      "request": {
        "headers": {
          "accept": {
            "caseInsensitive": true,
            "equalTo": "application/json"
          }
        },
        "method": "GET",
        "urlPathPattern": "/api/items/(UUID1|UUID2|UUID3|UUID4)"
      },
      "response": {
        "bodyFileName": "items-api/responses/retrieve/{{ request.pathSegments.[2] }}.json",
        "headers": {
          "content-type": "application/json"
        },
        "status": 200
      }
    },
    {
      "name": "Retrieve Items - 404 Not Found",
      "priority": 5, // arbitrary number that is higher than 1
      "request": {
        "headers": {
          "accept": {
            "caseInsensitive": true,
            "equalTo": "application/json"
          }
        },
        "method": "GET",
        "urlPathPattern": "/api/items/[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"
      },
      "response": {
        "status": 404
      }
    }
  ]
}
agoff
  • 5,818
  • 1
  • 7
  • 20
  • **agoff**, what exactly do you mean by `regex-matcher-for-calls-with-jsons`? I have the RegEx already in the stub — which basically matches any UUID. Or do you meant to have a specific set of UUIDs for the files, that for instance, have a fixed segment...or something around those lines. – x80486 Sep 22 '21 at 14:24
  • Yep, I mean the specific UUIDs that you want to match that have corresponding JSON files. `/api/items/(UUID1|UUID2|UUID3...)`. I can update the response to be more clear. – agoff Sep 22 '21 at 14:27