outofcoffee / imposter

Scriptable, multipurpose mock server. Run standalone mock servers, or embed mocks within your tests.
https://imposter.sh
Other
358 stars 59 forks source link

xPath not valid for capture? #602

Closed charles-slc closed 1 month ago

charles-slc commented 1 month ago

The docs have this example:

- path: "/users"
  method: POST
  capture:
    petName:
      xPath: "/env:Envelope/env:Body/pets:animal/pets:name"
      store: testStore
      xmlNamespaces:
        env: "http://schemas.xmlsoap.org/soap/envelope/"
        pets: "urn:com:example:petstore"

But I'm getting

14:01:37 INFO i.g.i.Imposter - Starting mock engine 4.0.0 14:01:37 DEBUG i.g.i.c.u.ConfigUtil - Loading configuration file: .\configs\gm-dds-config.yaml 14:01:38 DEBUG i.g.i.c.u.ConfigUtil - Loading configuration file: .\configs\single-response-config.yaml 14:01:38 DEBUG i.g.i.p.PluginManager - Loaded 5 plugin(s): [js-detector, store-detector, rest, js-graal, store-inmem] 14:01:39 ERROR i.v.c.i.l.c.VertxIsolatedDeployer - Failed in deploying verticle java.lang.RuntimeException: Error configuring plugin: rest at io.gatehill.imposter.plugin.PluginManagerImpl.configurePlugins(PluginManagerImpl.kt:133) ~[imposter.jar:?] at io.gatehill.imposter.plugin.PluginManagerImpl.startPlugins(PluginManagerImpl.kt:91) ~[imposter.jar:?] at io.gatehill.imposter.Imposter$start$1.invokeSuspend(Imposter.kt:132) ~[imposter.jar:?] at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) ~[imposter.jar:?] at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108) ~[imposter.jar:?] at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584) ~[imposter.jar:?] at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793) ~[imposter.jar:?] at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697) ~[imposter.jar:?] at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684) ~[imposter.jar:?] Caused by: java.lang.RuntimeException: Error loading configuration file: my-config.yml , reason: Unrecognized field "xPath" (class io.gatehill.imposter.plugin.config.capture.ItemCaptureConfig), not marked as ignorable (12 known properties: "requestBody", "const", "queryParam", "pathParam", "formParam", "phase", "requestHeader", "jsonPath", "key", "store", "expression", "enabled"])

with the following

---
plugin: rest 
basePath: "/dds"
system:
  xmlNamespaces:
    soap: "http://schemas.xmlsoap.org/soap/envelope/"
    star: "http://www.starstandard.org/STAR/5"

resources:
  - path: "/appointments"
    method: POST
    capture:
      serviceappointmentId:
        xPath: "/star:ProcessServiceAppointment/star:ProcessServiceAppointmentDataArea/star:ServiceAppointment/star:ServiceAppointmentHeader/star:SecondaryDealerNumberID"
        store: requestData
        xmlNamespaces:
          star: "http://www.starstandard.org/STAR/5"
    requestBody:
      xPath: "/star:ProcessServiceAppointment/star:ProcessServiceAppointmentDataArea"
      operator: Exists
    response:
      statusCode: 202
      content: "appt received"

note if I don't try to capture anything, the xPath match is working just fine.

Actually, what I'm hoping to capture is the entire request body.

outofcoffee commented 1 month ago

Hi @charles-slc, thank you for raising this issue with the documentation. You’re right that the example is wrong - sorry about that. It should be:


- path: "/users"
  method: POST
  capture:
    petName:
      store: testStore
      requestBody:
        xPath: "/env:Envelope/env:Body/pets:animal/pets:name"
        xmlNamespaces:
          env: "http://schemas.xmlsoap.org/soap/envelope/"
          pets: "urn:com:example:petstore"

This would make your config look as follows:


---
plugin: rest 
basePath: "/dds"
system:
  xmlNamespaces:
    soap: "http://schemas.xmlsoap.org/soap/envelope/"
    star: "http://www.starstandard.org/STAR/5"

resources:
  - path: "/appointments"
    method: POST
    capture:
      serviceappointmentId:
        store: requestData
        requestBody:
          xPath: "/star:ProcessServiceAppointment/star:ProcessServiceAppointmentDataArea/star:ServiceAppointment/star:ServiceAppointmentHeader/star:SecondaryDealerNumberID"
          xmlNamespaces:
            star: "http://www.starstandard.org/STAR/5"
    requestBody:
      xPath: "/star:ProcessServiceAppointment/star:ProcessServiceAppointmentDataArea"
      operator: Exists
    response:
      statusCode: 202
      content: "appt received"

I’ll keep this issue open until we can fix the docs.

outofcoffee commented 1 month ago

Also need to fix examples:

https://github.com/outofcoffee/imposter/blob/fada096e6061498d5285a638855269fada684b70/examples/rest/data-capture/imposter-config.yaml#L15

https://github.com/outofcoffee/imposter/blob/a6d8fb73d2acede329c5ef81ce1de22162cb38c9/examples/rest/response-template/imposter-config.yaml#L12

charles-slc commented 1 month ago

Thank you! That worked perfectly.

However, I actually just want to capture the entire request body. This seems to do the trick, though using jsonPath when I dealing with XML feels wrong 😆

    capture:
      serviceappointment:
        store: requestData
        requestBody:
          jsonPath: $

I tried xPath: $ which threw an error at runtime. Also xPath:"/" and xPath:"/*" which didn't throw an error and returned data via the system/stores REST API, However, the data returned was just the XML data values...no XML tags at all.

charles-slc commented 1 month ago

And FYI: I asked on SO about this, if you answer there I'll happily accept it. Otherwise in a few days I'll add the answer.

outofcoffee commented 1 month ago

Hi @charles-slc, thanks very much for the update.

Another way to capture the whole body would be using an expression, such as:

    capture:
      serviceappointment:
        store: requestData
        expression: "${context.request.body}"
outofcoffee commented 1 month ago

Thanks again, @charles-slc.

Docs and examples updated in v4.0.1