meeshkan / unmock-js

Fuzz test your REST API calls
https://unmock.io
93 stars 8 forks source link

Admin endpoint in unmock-server #376

Closed ksaaskil closed 4 years ago

ksaaskil commented 4 years ago

Add new HttpServer in unmock-server for setting state. This enables use cases where the mock server is running and user wants to add new services or modify their states. This issue does not cover adding such endpoints.

mikesol commented 4 years ago

Here are the design proposals I heard today. The general opinion is that the structure of the endpoint should mirror OpenAPI specs. From there, several proposals emerged. In each one, I will use https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml as the base, overriding the schema for /pets/{id}, retrieving the schema for /pets and deleting all non-200 responses from /pets

Using only GET and POST for everything all the time

Here, you can only GET the whole payload (a record of service names mapped to OpenAPI specs) and POST back the whole payload. Lots of stuff being sent to and from ports, but it is the most compact API in that we don't need to make any decisions about how to represent queries and mutations.

Using POST for all operations

In this model, post requests fuel the entire API.

Posting a new schema

{
  "action": "POST",
  "service": "petstore",
  "address": {
    "/pets/{id}": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema" : {
                  "properties": {
                    "name": {
                      "const" : "Fluffy
                    }
                  }
                }
              }
             }
          }
        }
      }
    }
  }
}

Getting a schema

{
  "action": "GET",
  "service": "petstore",
  "address": {
    "/pets": {
      "get": {
        "responses": {
          "200": {
            "content": {
              "application/json":  "schema"
             }
          }
        }
      }
    }
  }
}

Deleting requests that are not 200

{
  "action": "DELETE",
  "service": "petstore",
  "address": {
    "/pets": {
      "get": {
        "responses": "default"
      }
    }
  }
}

Using RESTful path for operation addresses

In this model, traditional REST verbs are used and paths are used to traverse the OpenAPI object.

Posting a new schema

$ curl -i -X POST http://localhost:8001/petstore/paths/=/pets/{id}/=/get/responses/200/content/=/application/json/=/schema/properties/=/name/= --data "{ \"const\": \"Fluffy\" }"

Getting a schema

$ curl -i -X GET http://localhost:8001/petstore/paths/=/pets=/get/responses/200/content/=/application/json/=/schema

Deleting requests that are not 200

$ curl -i -X DELETE http://localhost:8001/petstore/paths/=/pets=/get/responses/default
ksaaskil commented 4 years ago

Regarding the first suggestion, I don't think the address should be represented as JSON. The standard way to address JSON paths is the JSONPath syntax. JSONPath has implementations in most languages and it's designed for traversing and extracting data from JSON documents. See this example for a small demo in Python using python-jsonpath-rw.

So with JSONPath, the first example would be something like

POST /services/petstore
{
    "address": "paths.'/pets{id}'.get.responses.200.content.'application/json'.schema.properties",
    "content": "{\"name\": {\"const\": \"Fluffy\"}}
}

or, if using query parameters, in the POST request:

POST /services/petstore?path="paths.'/pets{id}'.get.responses.200.content.'application/json'.schema.properties"
{
    "name": {
        "const": "Fluffy"
    }
}

JSONPath also supports "wildcards" if one needs to update multiple values, it could get messy though.

ksaaskil commented 4 years ago

As for the second suggestion, I'm not sure if that's "REST" either? Are there examples of using paths like that in existing APIs? How would one document that in OpenAPI, for example?