Giter Club home page Giter Club logo

imposter's Introduction

Imposter: Scriptable, multipurpose mock server

CI

Mock server for REST APIs, OpenAPI (and Swagger) specifications, SOAP web services (and WSDL files), Salesforce and HBase APIs.

  • Run standalone mock servers in Docker, Kubernetes, AWS Lambda or on the JVM.
  • Embed mocks within your tests (JVM or Node.js) to remove external dependencies.
  • Script dynamic responses using JavaScript, Groovy or Java.
  • Capture data from requests, then store it or return a templated response.
  • Proxy an existing endpoint to replay its responses as a mock.

Imposter logo

Features

  • run standalone mocks in place of real systems
  • turn an OpenAPI/Swagger file or WSDL file into a mock API for dev or QA (use it before the real API is built)
  • decouple your integration tests from the cloud/back-end systems and take control of your dependencies
  • validate your API requests against an OpenAPI specification
  • capture data to retrieve later, or use in templates to for conditional responses
  • proxy an existing endpoint to replay its responses as a mock

Send dynamic responses:

  • Provide mock responses using static files or customise behaviour based on characteristics of the request.
  • Power users can control mock responses with JavaScript or Java/Groovy script engines.
  • Advanced users can write their own plugins in a JVM language of their choice.

Getting started

The quickest way to get up and running is to use the free cloud-hosted service at mocks.cloud

User documentation

Read the user documentation here

Tutorials


Mock types

Imposter provides specialised mocks for the following scenarios:

  • OpenAPI - Support for OpenAPI (and Swagger) API specifications.
  • REST - Mocks RESTful or plain HTTP APIs.
  • SOAP - Support for SOAP web services (and WSDL files).
  • HBase - Basic HBase mock implementation.
  • SFDC (Salesforce) - Basic Salesforce mock implementation.
  • WireMock - Support for WireMock mappings files.

These use a plugin system, so you can also create your own plugins, using any JVM language.

Example

$ imposter up

Starting server on port 8080...
Parsing configuration file: someapi-config.yaml
...
Mock server is up and running

Your mock server is now running! Here Imposter provides HTTP responses to simulate an API that accepts users and returns a dynamic response containing the user ID from the request.

$ curl -v -X PUT http://localhost:8080/users/alice

HTTP/1.1 201 Created
Content-Type: application/json

{ "userName": "alice" }

This is a trivial example, which you can extend with conditional logic, request validation, data capture and much more...

How to run Imposter

There are many ways to run Imposter.

Standalone mock server

Embedded in tests


Recent changes and Roadmap

For recent changes see the Changelog, or view the Roadmap.

Contributing

  • Pull requests are welcome.
  • PRs should target the develop branch.

Author

Pete Cornish ([email protected])

imposter's People

Contributors

benjvoigt avatar csokol avatar dependabot[bot] avatar driesva avatar kareem-habib avatar matejkobza avatar outofcoffee avatar pauturner avatar pcornish avatar raycw avatar snyk-bot avatar yanan-l avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imposter's Issues

Any options to connect groovy scripts to an Oracle Database?

Hi!

There is some way to connect a groovy script to an Oracle Database using ojdbc6.jar?

I've been trying to build muy own docker image from the openapi plugin image, and copy the .jar to some paths (lib), but always get a java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver

Thanks for reading!

Awesome project!!

Reload config command

As imposter does not auto reload, (does it? ), it would be great to have a command like /system/status that reloads the config file. Could be : /system/reload

This way, mockup server should be usable by many people without going on a protected server to restart service to reload.

A smart groovy script could be a workaround... until the script is broken !

Thank you.

Access Denied on file write for POST x-www-form-urlencoded request

First of all: this project is awesome and it saves us a lot of time. I really appreciate your work ๐Ÿ™Œ

We have a config for POST / request, it emulates Amazon STS Assume Role endpoint, so it looks like this:

---
plugin: rest
resources:
  - path: "/"
    method: POST
    response:
      staticData: |
        <AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
        ...

Locally we don't have any problem but when we try it in the Kubernetes cluster we started to see 500 Internal Errors with the exception of about access denied, vertx, and /file-uploads. I think it is because in our Pod we usually have a read-only filesystem, but Imposter tries to write something into it.

It is reproduced only with application/x-www-form-urlencoded in Content-Type and on a read-only filesystem, so it is my example of a request:

In [23]: httpx.post('http://imposter').content
Out[23]: b'<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">\n...\n'

In [24]: httpx.post('http://imposter',headers={'Content-Type': b'application/x-www-form-urlencoded; charset=utf-8'}).content
Out[24]: b'Internal Server Error'

Automatic example creation from model definition

Is it possible to implement example creation based on model definition in open api plugin (swagger ui)

Would want to implement something like that, because we need it, but dont want to give time into taht if this isnt possible

Question about mocking multiple path and sub arrays

From https://github.com/outofcoffee/imposter/blob/master/docs/rest_plugin.md#multiple-paths I understand that I can access element from an array like the examples of cats and dogs. however what if the array element also contains an array

Imagine I want to mock a call like cats/:id/owners and cats/:id/owners/:ownerid. where the first one would return the full array and the second only a specific owner using its id.

How can I mock a rest api like this one ?

Response in example and not examples

I have a spec file in which the example is provided in the definition.
Just because there is no examples it doesn't send a response.

Here's an example:

---
swagger: "2.0"
info:
  version: "1.0.0"
  title: "Swagger Petstore"
consumes:
- "application/json"
produces:
- "application/json"
paths:
  /pets:
    get:
      description: "Returns all pets from the system"
      produces:
        - "application/json"
      responses:
        "200":
          description: "A list of pets."
          schema:
            items:
              $ref: "#/definitions/Pet"
definitions:
  Pet:
    type: "object"
    required:
      - "id"
      - "name"
    properties:
      id:
        type: "integer"
        format: "int64"
      name:
        type: "string"
    example:
      "id": 101,
      "name": "Cat"

CORS support

Hi, Can you guide me on how to include CORS headers in API responses? Thank you.

OpenAPI plugin - JSON content type is not actually JSON

Hello!

I have a swagger spec that, in-part, looks like:

responses:
        Team:
            description: success
            schema:
                $ref: '#/definitions/Team'

            examples:
                application/json:
                    id: 10
                    name: Engineering

The JSON schema that is produced looks like:

"Team": {
      "description": "success",
      "examples": {
        "application/json": {
          "id": 10,
          "name": "Engineering"
        }
      },
      "schema": {
        "$ref": "#/definitions/Team"
      }
    },

If I hit the imposter API endpoint configured as such:

{
    "plugin": "com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl",
    "specFile": "apiv2.json",
}

I'm hoping to see the example returned. What I get is:

{id=10, name=Engineering}

which isn't valid JSON.

Looking at curl:

~ $ curl -v -H "Accept: application/json" http://127.0.0.1:8443/api/v2/teams/10
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8443 (#0)
> GET /api/v2/teams/10 HTTP/1.1
> Host: 127.0.0.1:8443
> User-Agent: curl/7.49.1
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 19
<
* Connection #0 to host 127.0.0.1 left intact

Imposter claims that this is JSON.

Watching debug output:

17:10:28.177 [vert.x-worker-thread-7] DEBUG com.gatehill.imposter.service.ResponseServiceImpl - Using default response behaviour for request: http://127.0.0.1:8443/api/v2/teams/10
17:10:28.179 [vert.x-worker-thread-7] DEBUG com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl - Exact example match found (application/json) from specification
17:10:28.179 [vert.x-worker-thread-7] INFO  com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl - Serving mock example for URI http://127.0.0.1:8443/api/v2/teams/10 and status code 200 (response body 19 bytes)

It looks like the example is returned, but not as encoded JSON, but as a string representation of a Map...

Version of the swagger UI (seems to need updating)

Hey

I have been trying mock a OpenAPI version 3.0 and run into issues where the http://localhost:8080/_spec do not send path parameters with the request to the server.

It generates this url http://localhost/v1/screen/, which should have been http://localhost/v1/screen/497f6eca-6276-1596-bfeb-53ceb43a6f54. The OpenAPI definition works perfectly in https://editor.swagger.io/.

I can see that the swagger UI files in https://github.com/outofcoffee/imposter/tree/master/plugin/openapi/src/main/html have not be updated and the current release is v3.49.0 where the one in imposter is v3.24.3.

Screenshot 2021-06-01 at 22 38 37

Would it be possible to update the swagger UI version to fix this issue

Should provide a withScript(String) function

It seems impossible to load a script using withFile(filename).template(). In order to have different scripts doing different actions but share common code (like decoding parameters, storing in stores etc..) a function withScript(String) would be useful. Of course the request store should be available through all those scripts for the whole life cycle of the current HTTP request like it is today even if multiple scripts are called.

For instance I'd like to do something like

# mock-config.yaml
plugin: rest

resources:
  - path: /my/path
    method: POST
    response:
      scriptFile: dispatcher.groovy
// dispatcher.groovy
def requestStore = stores.open('request')
def queryParams = context.request.body.split('&').collectEntries {
    param -> param.split('=').collect { URLDecoder.decode(it) }
}

// store all important params in request store
...

// do some other stuff like storing calculating values in request store 
...
// check if queryParams.wsfunction is known and call the corresponding script
if (....){
      respond()
          .withScript("${queryParams.wsfunction}.groovy")
else{
      respond()
          .withStatusCode(400)
          .skipDefaultBehaviour()
}

Responses reference not followed

Firstly thankyou for this tool. I didn't think it would be so hard to find a tool that would mock/stub the spec and return example responses.

However the ExampleService assumes that the response is inlined ie:

{
  "responses": {
    "200": {
      "description": "Successful response",
      "content": {
        "application/json": {
          "schema": {
            ...
          },
          "examples": {
            "application/json": {
              "value": {
                ...               
              }
            }
          }
        }
      }
    }
  }
}

If however, I use a Reference Object the example is not found ie:

{
  "responses": {
    "200": {
      "$ref": "#/components/responses/myResponse"
    }
  }
}

Unfortunately my entire spec uses response references, so for me to use this tool I need the reference to be followed.

Imposter to return a response from examples as a round-robin

Currently, from the open api spec, when I start imposter , I'm able to start server and access my endpoint via API. When I invoke API, I'm able to get the response which I have configured as example in open api spec. If I configure, multiple examples, it's always returning the last example mentioned in openapi spec. Is there an option that we can configure to pick the reponse like a round robin behavior on the examples available rather than picking the last example all the time

Fails on Kubeflow Pipelines swagger specification

https://github.com/kubeflow/pipelines/blob/master/backend/api/swagger/kfp_api_single_file.swagger.json

docker run -ti -p 8080:8080 \
    -v $(pwd)/config:/opt/imposter/config \
    outofcoffee/imposter-openapi \
    --configDir /opt/imposter/config

16:21:21 DEBUG c.g.i.s.ImposterLauncher - No plugins specified - attempting to load defaults
16:21:21 DEBUG c.g.i.s.ImposterVerticle - Initialising mock server
16:21:21 INFO  c.g.i.Imposter - Starting mock engine
16:21:21 DEBUG c.g.i.Imposter - Loading configuration file: /opt/imposter/config/openapi2-config.json
16:21:21 INFO  c.g.i.Imposter - Loaded 1 plugin configuration files from: [/opt/imposter/config]
16:21:21 DEBUG c.g.i.Imposter - Registered plugin com.gatehill.imposter.plugin.detector.PluginDetectorImpl
16:21:21 DEBUG c.g.i.Imposter - 1 plugins provided by com.gatehill.imposter.plugin.detector.PluginDetectorImpl
16:21:21 DEBUG c.g.i.Imposter - Registered plugin com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl
16:21:21 INFO  c.g.i.Imposter - Loaded 2 plugins
16:21:22 DEBUG c.g.i.p.o.u.OpenApiVersionUtil - Using version: V2 parser for: /opt/imposter/config/kfp_api_single_file.swagger.json
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: GET -> /apis/v1beta1/runs
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: POST -> /apis/v1beta1/runs
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: DELETE -> /apis/v1beta1/runs/:id
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: POST -> /apis/v1beta1/runs/:id:archive
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: POST -> /apis/v1beta1/runs/:id:unarchive
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: GET -> /apis/v1beta1/runs/{run_id}
16:21:22 DEBUG c.g.i.p.o.OpenApiPluginImpl - Adding mock endpoint: GET -> /apis/v1beta1/runs/{run_id}/nodes/{node_id}/artifacts/{artifact_name}:read
java.util.regex.PatternSyntaxException: Illegal repetition near index 18
/apis/v1beta1/runs/{run_id}/nodes/{node_id}/artifacts/{artifact_name}(?<p0>[^/]+)
                  ^
	at java.util.regex.Pattern.error(Pattern.java:1957)
	at java.util.regex.Pattern.closure(Pattern.java:3159)
	at java.util.regex.Pattern.sequence(Pattern.java:2136)
	at java.util.regex.Pattern.expr(Pattern.java:1998)
	at java.util.regex.Pattern.compile(Pattern.java:1698)
	at java.util.regex.Pattern.<init>(Pattern.java:1351)
	at java.util.regex.Pattern.compile(Pattern.java:1028)
	at io.vertx.ext.web.impl.RouteImpl.createPatternRegex(RouteImpl.java:397)
	at io.vertx.ext.web.impl.RouteImpl.setPath(RouteImpl.java:353)
	at io.vertx.ext.web.impl.RouteImpl.<init>(RouteImpl.java:68)
	at io.vertx.ext.web.impl.RouterImpl.route(RouterImpl.java:89)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$handlePathOperations$4(OpenApiPluginImpl.java:134)
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.handlePathOperations(OpenApiPluginImpl.java:128)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$null$0(OpenApiPluginImpl.java:104)
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$configureRoutes$1(OpenApiPluginImpl.java:103)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.configureRoutes(OpenApiPluginImpl.java:98)
	at com.gatehill.imposter.server.ImposterVerticle.lambda$configureRoutes$4(ImposterVerticle.java:86)
	at java.util.HashMap$Values.forEach(HashMap.java:981)
	at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080)
	at com.gatehill.imposter.server.ImposterVerticle.configureRoutes(ImposterVerticle.java:86)
	at com.gatehill.imposter.server.ImposterVerticle.lambda$start$0(ImposterVerticle.java:50)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:271)
	at io.vertx.core.impl.TaskQueue.lambda$new$0(TaskQueue.java:60)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
16:21:22 ERROR i.v.c.i.l.c.VertxIsolatedDeployer - Failed in deploying verticle
java.util.regex.PatternSyntaxException: Illegal repetition near index 18
/apis/v1beta1/runs/{run_id}/nodes/{node_id}/artifacts/{artifact_name}(?<p0>[^/]+)
                  ^
	at java.util.regex.Pattern.error(Pattern.java:1957) ~[?:1.8.0_212]
	at java.util.regex.Pattern.closure(Pattern.java:3159) ~[?:1.8.0_212]
	at java.util.regex.Pattern.sequence(Pattern.java:2136) ~[?:1.8.0_212]
	at java.util.regex.Pattern.expr(Pattern.java:1998) ~[?:1.8.0_212]
	at java.util.regex.Pattern.compile(Pattern.java:1698) ~[?:1.8.0_212]
	at java.util.regex.Pattern.<init>(Pattern.java:1351) ~[?:1.8.0_212]
	at java.util.regex.Pattern.compile(Pattern.java:1028) ~[?:1.8.0_212]
	at io.vertx.ext.web.impl.RouteImpl.createPatternRegex(RouteImpl.java:397) ~[imposter-openapi.jar:?]
	at io.vertx.ext.web.impl.RouteImpl.setPath(RouteImpl.java:353) ~[imposter-openapi.jar:?]
	at io.vertx.ext.web.impl.RouteImpl.<init>(RouteImpl.java:68) ~[imposter-openapi.jar:?]
	at io.vertx.ext.web.impl.RouterImpl.route(RouterImpl.java:89) ~[imposter-openapi.jar:?]
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$handlePathOperations$4(OpenApiPluginImpl.java:134) ~[imposter-openapi.jar:?]
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[?:1.8.0_212]
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.handlePathOperations(OpenApiPluginImpl.java:128) ~[imposter-openapi.jar:?]
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$null$0(OpenApiPluginImpl.java:104) ~[imposter-openapi.jar:?]
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684) ~[?:1.8.0_212]
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$configureRoutes$1(OpenApiPluginImpl.java:103) ~[imposter-openapi.jar:?]
	at java.util.ArrayList.forEach(ArrayList.java:1257) ~[?:1.8.0_212]
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.configureRoutes(OpenApiPluginImpl.java:98) ~[imposter-openapi.jar:?]
	at com.gatehill.imposter.server.ImposterVerticle.lambda$configureRoutes$4(ImposterVerticle.java:86) ~[imposter-openapi.jar:?]
	at java.util.HashMap$Values.forEach(HashMap.java:981) ~[?:1.8.0_212]
	at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080) ~[?:1.8.0_212]
	at com.gatehill.imposter.server.ImposterVerticle.configureRoutes(ImposterVerticle.java:86) ~[imposter-openapi.jar:?]
	at com.gatehill.imposter.server.ImposterVerticle.lambda$start$0(ImposterVerticle.java:50) ~[imposter-openapi.jar:?]
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:271) ~[imposter-openapi.jar:?]
	at io.vertx.core.impl.TaskQueue.lambda$new$0(TaskQueue.java:60) ~[imposter-openapi.jar:?]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_212]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_212]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_212]
java.util.regex.PatternSyntaxException: Illegal repetition near index 18
/apis/v1beta1/runs/{run_id}/nodes/{node_id}/artifacts/{artifact_name}(?<p0>[^/]+)
                  ^
	at java.util.regex.Pattern.error(Pattern.java:1957)
	at java.util.regex.Pattern.closure(Pattern.java:3159)
	at java.util.regex.Pattern.sequence(Pattern.java:2136)
	at java.util.regex.Pattern.expr(Pattern.java:1998)
	at java.util.regex.Pattern.compile(Pattern.java:1698)
	at java.util.regex.Pattern.<init>(Pattern.java:1351)
	at java.util.regex.Pattern.compile(Pattern.java:1028)
	at io.vertx.ext.web.impl.RouteImpl.createPatternRegex(RouteImpl.java:397)
	at io.vertx.ext.web.impl.RouteImpl.setPath(RouteImpl.java:353)
	at io.vertx.ext.web.impl.RouteImpl.<init>(RouteImpl.java:68)
	at io.vertx.ext.web.impl.RouterImpl.route(RouterImpl.java:89)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$handlePathOperations$4(OpenApiPluginImpl.java:134)
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.handlePathOperations(OpenApiPluginImpl.java:128)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$null$0(OpenApiPluginImpl.java:104)
	at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.lambda$configureRoutes$1(OpenApiPluginImpl.java:103)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at com.gatehill.imposter.plugin.openapi.OpenApiPluginImpl.configureRoutes(OpenApiPluginImpl.java:98)
	at com.gatehill.imposter.server.ImposterVerticle.lambda$configureRoutes$4(ImposterVerticle.java:86)
	at java.util.HashMap$Values.forEach(HashMap.java:981)
	at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1080)
	at com.gatehill.imposter.server.ImposterVerticle.configureRoutes(ImposterVerticle.java:86)
	at com.gatehill.imposter.server.ImposterVerticle.lambda$start$0(ImposterVerticle.java:50)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:271)
	at io.vertx.core.impl.TaskQueue.lambda$new$0(TaskQueue.java:60)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

No response with a non existing ID

When an unknown ID is used imposter says it can't find it

14:59:28 ERROR i.g.i.p.s.SfdcPluginImpl - Account SObject with ID: 0015000000VALDtBBB not found

but it doesn't send a correct response to ForceApi and I get

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
	at Main_Scriptlet_fc96736f82df81e8$Companion.main(Main_Scriptlet_fc96736f82df81e8.kt:6)
	at Main_Scriptlet_fc96736f82df81e8.main(Main_Scriptlet_fc96736f82df81e8.kt)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.jetbrains.kotlin.runner.AbstractRunner.run(runners.kt:64)
	at org.jetbrains.kotlin.runner.Main.run(Main.kt:176)
	at org.jetbrains.kotlin.runner.Main.main(Main.kt:186)
Caused by: java.lang.RuntimeException: java.io.IOException: Stream closed
	at com.force.api.http.Http.send(Http.java:118)
	at com.force.api.ForceApi.apiRequest(ForceApi.java:499)
	at com.force.api.ForceApi.getSObject(ForceApi.java:206)
	at Scriptlet_fc96736f82df81e8.<init>(scriptlet.fc96736f82df81e8.kts:25)
	... 13 more
Caused by: java.io.IOException: Stream closed
	at java.base/java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:165)
	at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:290)
	at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:351)
	at java.base/java.io.FilterInputStream.read(FilterInputStream.java:107)
	at com.force.api.http.Http.readResponse(Http.java:57)
	at com.force.api.http.Http.send(Http.java:113)
	... 16 more

JSON property matching from request body in script

Hi, is there a way to get a specific property of a JSON that is being sent in a request in a groovy script? context.request.body returns a plain string and I'm unable to use groovy.json.JsonSlurper to parse as I'm getting unable to resolve class groovy.json.JsonSlurper when I try to import it.

multiple rules for same path not working

I'm trying to use this feature that was introduced in 2.9.0, however it doesn't work. Here is the configuration I use

plugin: rest

resources:
- method: GET
  path: /example
  requestBody:
    jsonPath: $.foo
    value: bar
  response:
    statusCode: 500

- method: GET
  path: /example
  requestBody:
    jsonPath: $.baz
    value: 99
  response:
    statusCode: 302

But when trying to query the same path with a different body I would expect the 1st rule, the 2nd rule, or none of them to match. However I see 3 issues:

  • the value for baz which is 99 matches only if use string "99" in the body but not integer 99
  • imposter returns the response of the 1st rule instead of the 2nd rule when it matches the 2nd (Using default HTTP 500 response behaviour)
  • imposter returns the response of the 1st rule when there is nothing that matches (Using default HTTP 500 response behaviour)

Here are my different tests

Query with baz having value "99" (string) which should not match any rule

/ # curl -v -d '{"baz": "99"}' -X GET http://localhost:8888/example
*   Trying 127.0.0.1:8888...
* Connected to localhost (127.0.0.1) port 8888 (#0)
> GET /example HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.79.1
> Accept: */*
> Content-Length: 13
> Content-Type: application/x-www-form-urlencoded
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
< X-Imposter-Request: 2b60c533-ac0e-4e7d-9693-522fe17ff8c7
< Server: imposter
< content-length: 0
<
* Connection #0 to host localhost left intact

imposter side

22:04:30 DEBUG i.g.i.s.ResourceServiceImpl - Matched response config for GET /example
22:04:30 DEBUG i.g.i.s.ResponseServiceImpl - Using default HTTP 500 response behaviour for request: GET http://localhost:8888/example
22:04:30 INFO  i.g.i.p.r.RestPluginImpl - Handling GET object request for: http://localhost:8888/example
22:04:30 INFO  i.g.i.s.ResponseServiceImpl - Response file and data are blank - returning empty response for [a36b0a8e-9d3c-42ed-baf8-d56baae04381] GET http://localhost:8888/example

Query with baz having value 99 (integer) which should match 2nd rule

/ # curl -v -d '{"baz": 99}' -X GET http://localhost:8888/example
*   Trying 127.0.0.1:8888...
* Connected to localhost (127.0.0.1) port 8888 (#0)
> GET /example HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.79.1
> Accept: */*
> Content-Length: 11
> Content-Type: application/x-www-form-urlencoded
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
< X-Imposter-Request: 922038ea-773c-40f7-a1f9-fcf63647a90d
< Server: imposter
< content-length: 0
<
* Connection #0 to host localhost left intact

imposter side (See that it doesn't match response config)

22:04:49 DEBUG i.g.i.s.ResponseServiceImpl - Using default HTTP 500 response behaviour for request: GET http://localhost:8888/example
22:04:49 INFO  i.g.i.p.r.RestPluginImpl - Handling GET object request for: http://localhost:8888/example
22:04:49 INFO  i.g.i.s.ResponseServiceImpl - Response file and data are blank - returning empty response for [4514ace6-ddd0-4e11-b867-0a38e756fec5] GET http://localhost:8888/example

Query with neither foo nor baz having expected values which should not match any rule but still returns default response from 1st rule. Why is it the default ? It shouldn't match at all

/ # curl -v -d '{"no-known-key": "a-value"}' -X GET http://localhost:8888/example
*   Trying 127.0.0.1:8888...
* Connected to localhost (127.0.0.1) port 8888 (#0)
> GET /example HTTP/1.1
> Host: localhost:8888
> User-Agent: curl/7.79.1
> Accept: */*
> Content-Length: 27
> Content-Type: application/x-www-form-urlencoded
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
< X-Imposter-Request: 6238b636-b576-4900-9f5b-6c2a63c0b67d
< Server: imposter
< content-length: 0
<
* Connection #0 to host localhost left intact

imposter side

22:06:25 DEBUG i.g.i.s.ResponseServiceImpl - Using default HTTP 500 response behaviour for request: GET http://localhost:8888/example
22:06:25 INFO  i.g.i.p.r.RestPluginImpl - Handling GET object request for: http://localhost:8888/example
22:06:25 INFO  i.g.i.s.ResponseServiceImpl - Response file and data are blank - returning empty response for [6238b636-b576-4900-9f5b-6c2a63c0b67d] GET http://localhost:8888/example

openapi spec 3.*

Hi,

do you intent to support openapi spec 3.* in the near future?

Shorten log line prefix

This:

11:56:26.779 [vert.x-eventloop-thread-0] INFO  com.gatehill.imposter.server.ImposterVerticle - Starting mock server on 0.0.0.0:8443

...is too long. Should be:

11:56:26 INFO c.g.i.s.ImposterVerticle - Starting mock server on 0.0.0.0:8443

No API path found that matches request

I believe I am passing a valid request for the specification

swagger: "2.0"
info:
  version: "2021-11-03T14:58:25Z"
  title: "charges-dev"
host: "localhost:8080"
basePath: "/charges"
schemes:
- "https"
- "http"
  paths:
    /myendoint:
      post:
        tags:
        - "tags"
        summary: "Post endpoint"
        description: "takes a payload
        consumes:
        - "application/json"
        produces:
        - "application/json"
        parameters:
        - in: "body"
          name: "PostBody"
          description: "Post Body"
          required: true
          schema:
            $ref: "#/definitions/PostBodyDef

curl --location --request POST 'localhost:8080/charges/myendpoint/' \ --header 'Content-Type: application/json' \ --data-raw ' [ { ....

Paths match
Verbs match
Payload matches

Config

plugin: openapi specFile: output.yml validation: request: true levels: validation.request.body.missing: WARN validation.request.body.unexpected: WARN validation.request.path.missing: ERROR

What else do I need to match?

Publish imposter to Maven central

It would be nice for testing if importer would be available in Maven central and it could be handled same way as other (test) dependencies.

ARM64 Support?

Hello! Thank you for this project!

Any plans to publish a docker image with arm64 support? This would be very helpful for those running the project on arm based machines like the M1 mac chips. Thanks again!

Letter case of predefined specification properties

Hi,

first I would like to say thanks for this awesome software. I've been using it for a few OAS projects now and it's really great and useful.

I've noticed a little problem a couple of times though. When using Swagger UI, some things do not work. I've done some research and the problem seems to be, that some property values are transformed to uppercase when imposter produces the combined.json.

For example, when securitySchemes are defined in the spec with type: http, in combined.json it reads type: HTTP. Swagger UI doesn't like this, apparently, and so the authentication popup is blank when it opens. From the OpenAPI documentation it looks like the value should be lowercase.

The same happens with the style property of operation parameters.

I'm building my own docker container based on outofcoffee/imposter-openapi.

Can you give me a hint on how to fix this?

Thanks!
Jan

Duplicate responses

Hi!

I have a swagger.json file that responds with the same response:
The response for this get:
"/comments": {
"get": {
"summary": "Get Comments",
"description": "Get the comments based on data",
"operationId": "getComments",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "Successful operation",
"headers": {},
"schema": {
"$ref": "#/definitions/CommentResponse"
},
"examples": {
"application/json" : "{\n"results" : 1, \n"items" : [\n\t{\n\t"id" : 1,\n\t"user" : "user",\n\t"creationTimestamp" : "2019-09-13T14:32:35.203Z",\n\t"content" : "This is a comment"]}"
}
},

Is exactly as the one for the following:
"/comments/users": {
"get": {
"summary": "Get all users",
"operationId": "getUsers",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "Successful operation",
"schema": {
"$ref": "#/definitions/UsersResponse"
},
"examples": {
"application/json" : "{\n"results" : 4, \n"items" : [\n\t{\n\t\t "name" : "user1" \n\t},\n\t{ \n\t\t "name" : "user2" \n\t}, \n\t{ \n\t\t "name" : "user3" \n\t}, \n\t{ \n\t\t"name" : "user4" \n\t}"
}
},

I didn't used any groovy scripts or something else. Only one -config file to get the swagger.json file and one docker-compose to run the docker image.

Any ideas why this is happenning?

Multiple mock services inside a single JVM

I'm running mutiple Imposter instances (openAPI) as docker containers which once a while are crashing with exit code 137 because they are allocating too much memory.

I was wondering if we could mock multiple services inside a single JVM. Is there any way to pass multiple configurations (one for each mock service) to Imposter? I guess this way the total amount of memory would be reduced.

I've also noticed Imposter uses an OpenJDK 8 Docker Image and according to its documentation:

Inside Linux containers, OpenJDK versions 8 and later can correctly detect container-limited number of CPU cores and available RAM.

In OpenJDK 11 this is turned on by default. In versions 8, 9, and 10 you have to enable the detection of container-limited amount of RAM using the following options:

$ java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap...

I'm not sure, but maybe those flags could help to keep memory consumption under control.

SFDC plugin - auth response has no Content-type header

SFDC plugin

Test Step - Send a HTTP POST request to sfdc auth endpoint.

Expected Outcome - Response should contain a Content-Type header

Observe Outcome - The http response from the auth endpoint has no content type header.

I think it should have Content-Type: application/json

Will put in a PR

Example response from imposter service sfdc plugin is:

HTTP/1.1 200 OK
Content-Length: 74

{"access_token":"dummyAccessToken","instance_url":"http://localhost:8443"}

simple-salesforce support

Hi,
is it possible to run sfdc with simple_salesforce as a client?
I run the mock:

docker run -ti -p 8080:8080   
                      -p 443:443  
                      -v $(pwd)/config:/opt/imposter/config 
                      -v $(pwd)/keystore:/opt/imposter/keystore    
                      outofcoffee/imposter-sfdc -c /opt/imposter/config 
                                                               --tlsEnabled 
                                                               --listenPort 443
                                                               --serverUrl http://localhost:443 
                                                               --keystorePath /opt/imposter/keystore/ssl.jks
                                                               --keystorePassword password

Then I just use:

from simple_salesforce import Salesforce
sf = Salesforce(instance_url='https://127.0.0.1', session_id='')
sf.Contact.create({'LastName':'Smith','Email':'[email protected]'})

And get error:

requests.exceptions.SSLError: HTTPSConnectionPool(host='127.0.0.1', port=443): Max retries exceeded with url: /services/data/v38.0/sobjects/Contact/ (Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))

If you know a way to make simple-salesforce work without ssl, it will also help me.
Thanks.

Take examples from models as well as responses

Relates to #12 and #29.

Background

Today, Imposter uses examples specified in the responses section of an API. In the OpenAPI specification it is also possible to have examples in the model definitions.

Scope

Collect examples from model definitions, and use them if a response example does not exist.

Swagger UI Try it out functionality is broken. Not seeing path parameter values entered

Hello,

Great tool. I absolutely think this is so cool. One issue I did run into tho is that when I try to use the swagger api specification UI and need to enter a value for a path parameter, the curl statement shows as if i did not enter the param value and instead it places a comma in where the path parameter value should be and then results in a response of

Resource not found

I am using the latest docker image and tried both imposter-openapi and imposter and same issue.

I am running on mac Big Sur 11.6 and google chrome Version 95.0.4638.69 (Official Build) (x86_64)

outofcoffee/imposter-openapi ports params is ignored

hi can i assign other port like this e.g: 8084. when i docker run command the port is ignored.

docker run --rm -ti --network host  -p 8084:8080 \ 
    -v $(pwd):/opt/imposter/config \
    outofcoffee/imposter-openapi

Valid Response Codes Not Honored

When a path in the swagger specifies a specific set of response codes, a 200 response is always returned. Assume the following swagger fragment:

paths:
    '/Order/{orderId}':
        put:
          consumes:
            - application/json
          produces: []
          parameters:
            - name: order
              in: body
              required: false
              schema:
                $ref: '#/definitions/Order'
          responses:
            '202':
              description: Request to put the order has been accepted.
            '400':
              description: Bad Request

Imposter seems to always respond with a 200 response and not a 202.

Getting same responses for different paths if paths are like /tests and /tests/results

Hi,

I am facing an issue where I am receiving same responses if the request paths overlap like if request 1 path is /tests
and request 2 path is /tests/results and I am receiving the response of /tests even if I am trying out the second request /tests/results, this is happening in case of both the _spec url with swaggerUI and while requesting via postman as well, is there a configuration that I am missing?

This same issue was describe in the following link
#34 (comment)
but it was closed without any resolution.

Is there a mechanism to test error codes?

I use OpenAPI. I have multiple responses for each path, including error responses like 404, 409 etc.

Is there a way to trigger an API call to to test error codes?

Example:

    /rest/api/2/project/{projectIdOrKey}:
      get:
        tags:
          - jira
        summary: get project
        operationId: getProject
        description: Gets information about a project
        parameters:
          - in: path
            name: projectIdOrKey
            schema:
              type: string
            required: true
            example: TEST
            description: Numeric ID or key of the project
        responses:
          '200':
            description: Success
            content:
              application/json:
                schema:
                  $ref: '#/components/schemas/Project'
          '404':
            description: The project is not found, or the calling user does not have permission to view it.
            content:
              application/json:
                schema:
                  $ref: '#/components/schemas/Error'         

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.