How to generate JSON examples from OpenAPI/Swagger model definition?
Asked Answered
C

4

21

I'm building a fuzzer for a REST API that has an OpenAPI (Swagger) definition.

I want to test all available path from the OpenAPI definition, generate data to test the servers, analyse responses code and content, and to verify if the responses are conform to the API definition.

I'm looking for a way to generate data (JSON object) from model definitions.

For example, given this model:

...
"Pet": {
  "type": "object",
  "required": [
    "name",
    "photoUrls"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "format": "int64"
    },
    "category": {
      "$ref": "#/definitions/Category"
    },
    "name": {
      "type": "string",
      "example": "doggie"
    },
    "photoUrls": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "tags": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/Tag"
      }
    },
    "status": {
      "type": "string",
      "description": "pet status in the store"
    }
  }
}

I want to generate random data and get something like this:

{
  "id": 0,
  "category": {
    "id": 0,
    "name": "string"
  },
  "name": "doggie",
  "photoUrls": [
    "string"
  ],
  "tags": [
    {
      "id": 0,
      "name": "string"
    }
  ],
  "status": "string"
}
Croce answered 31/12, 2016 at 13:35 Comment(0)
K
10

The Swagger Inflector library has the ExampleBuilder class exactly for this purpose. It lets you generate JSON, XML and YAML examples from models in an OpenAPI (Swagger) definition.

OpenAPI 2.0 example

To work with OpenAPI 2.0 (swagger: '2.0') definitions, use Swagger Java libraries 1.x.

import io.swagger.parser.SwaggerParser;
import io.swagger.models.*;
import io.swagger.inflector.examples.*;
import io.swagger.inflector.examples.models.Example;
import io.swagger.inflector.processors.JsonNodeExampleSerializer;
import io.swagger.util.Json;
import io.swagger.util.Yaml;
import java.util.Map;
import com.fasterxml.jackson.databind.module.SimpleModule;

...

// Load your OpenAPI/Swagger definition
Swagger swagger = new SwaggerParser().read("http://petstore.swagger.io/v2/swagger.json");

// Create an Example object for the Pet model
Map<String, Model> definitions = swagger.getDefinitions();
Model pet = definitions.get("Pet");
Example example = ExampleBuilder.fromModel("Pet", pet, definitions, new HashSet<String>());
// Another way:
// Example example = ExampleBuilder.fromProperty(new RefProperty("Pet"), swagger.getDefinitions());

// Configure example serializers
SimpleModule simpleModule = new SimpleModule().addSerializer(new JsonNodeExampleSerializer());
Json.mapper().registerModule(simpleModule);
Yaml.mapper().registerModule(simpleModule);

// Convert the Example object to string

// JSON example
String jsonExample = Json.pretty(example);
System.out.println(jsonExample);

// YAML example
String yamlExample = Yaml.pretty().writeValueAsString(example);
System.out.println(yamlExample);

// XML example (TODO: pretty-print it)
String xmlExample = new XmlExampleSerializer().serialize(example);
System.out.println(xmlExample);

OpenAPI 3.0 example

For an OpenAPI 3.0 example, see this answer. You need version 2.x of Swagger Java libraries, and update the imports and class names appropriately, e.g. change io.swagger.parser.SwaggerParser to io.swagger.v3.parser.OpenAPIV3Parser and so on.

Kalikalian answered 2/7, 2018 at 10:20 Comment(5)
This works like a peach, almost after a year of searching for a solution I found this!Melinamelinda
Unfortunately the ExampleBuilder does not respect the minLength and maxLength properties when creating string fields in JSON output (it always puts 'string' in a string field). This can result in 'malformed' JSON. You can work around this by creating your own StringProperty objects but that kind of defeats the purposes of having a builder.Oto
@Oto you can open an issue at github.com/swagger-api/swagger-inflector/issues (or, better yet, submit a PR). As a workaround you can modify your API definition to provide a custom example for each property, and Inflector will use those examples.Kalikalian
swagger-inflector, only works when the schema is defined simple and basic. It does not recognize oneOf, anyOf, allOf, it does not handle any references using $ref, it does not follow any pattern.Yearling
@Yearling ExampleBuilder supports allOf, $ref, oneOf and anyOf. With oneOf/anyOf, it should use the first subschema. If you get incorrect/incomplete examples, please open an issue at github.com/swagger-api/swagger-inflector/issues. Make sure to check your OpenAPI definition for syntax errors using editor.swagger.io and/or other validators. You can also work around ExampleBuilder's limitations by providing your own example for some schemas/properties in your API definition.Kalikalian
D
1

My experience:

  1. go to http://editor.swagger.io
  2. File -> Import file (to load my own Swagger description)
  3. Generate client -> Java (in my case)
  4. Download and extract the client
  5. Import it's model package into any simple project, instantiate and fill model's classes with the data you need
  6. Marshall the instantiated objects into the JSON (My case - Gson, because the generated model is annotated by Gson annotations)
  7. Profit

In short: generating client (java-client in my case) based on Swagger definition, filling it's model and marshalling the result.

Dinger answered 12/7, 2017 at 9:19 Comment(1)
This has nothing to do with the OP question which is how to generate fake data for the purposes of fuzzingSidle
S
1

Just put your model in https://json-schema-faker.js.org/ and off you go.

Your provided schema works as is with minor modifications: remove "Pets" and add definitions for "Category" and "Tag". See below as an example.

Then click "Generate" and you get fake data back. It appears that this can all be done programmatically via the libraries if you don't want to go through the website (haven't tried that myself though).

{
  "definitions": {
    "description": "making this up so all refs resolve",
    "Category": {
      "type": "string"
    },
    "Tag": {
      "type": "string"
    }
  },
  "comment": "From here on down, it's exactly the same as the OP schema",
  "type": "object",
  "required": [
    "name",
    "photoUrls"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "format": "int64"
    },
    "category": {
      "$ref": "#/definitions/Category"
    },
    "name": {
      "type": "string",
      "example": "doggie"
    },
    "photoUrls": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "tags": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/Tag"
      }
    },
    "status": {
      "type": "string",
      "description": "pet status in the store"
    }
  }
}
Sidle answered 20/12, 2020 at 2:18 Comment(2)
json-schema-faker.js.org doesn't seem to work in any way I can see. I paste my OpenAPI description in the left panel. There are no other opportunities to influence the input. I click generate and just get the OpenAPI description back, no actual requests or responses.Indigested
@Indigested as of 2024-06-12 it seems to work just fine for me (using Chrome) and if for some reason the site is failing, you can run locally from github.com/json-schema-faker/json-schema-faker. Note: I have zero affiliation/relation with json-schema-faker. I just think it's useful and helps answer this questionSidle
D
0

I want to mention some tools that were not mentioned:

Dongdonga answered 13/6 at 13:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.