We are using Swagger 2.0 for our documentation. We are Pro-grammatically creating swagger 2.0 spec straight out our data design documents.
Our Model is very complex and nested. I would like to understand can we define nested array objects defined inline.
for e.g :
{
"definitions": {
"user": {
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"address": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["home",
"office"]
},
"line1": {
"type": "string"
}
},
"Person": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
}
}
}
}
}
}
}
We have many cases where we encounter this in our model and defining a #ref is not an option that we want to consider at this time. We need this to handled inline.
As per the following post : https://github.com/swagger-api/swagger-editor/issues/603#evenenter code heret-391465196 looks like its not supported to handle nested array objects defined inline.
Since lot of big enterprise's have a very complex data model we would like to have this this feature to be supported in swagger 2.0 spec.
Is there any thought on this feature to be added.
You document is just invalid and this is not about nested arrays: the property Person is not allowed in a Swagger 2.0 schema inside items.
The only allowed properties in a schema are: $ref, format, title, description, default, multipleOf, maximum, exclusiveMaximum, minimum, exclusiveMinimum, maxLength, minLength, pattern, maxItems, minItems, uniqueItems, maxProperties, minProperties, required, enum, additionalProperties, type, items, allOf, properties, discriminator, readOnly, xml, externalDocs, example.
Related
I am looking to convert JSON to Avro without altering the shape of the data
A nested field in the JSON contains a variable number of keys, which are never known in advance. The record that branches off of each of these unknown nodes however is of known, well-defined shape.
An example of this input data is as shown below
{
"customers": {
"paul_ince": {
"name": "Mr Paul Ince",
"age": 54
},
"kim_kardashian": {
"name": "Ms Kim Kardashian",
"age": 41
},
"elon_musk": {
"name": "Elon Musk, Technoking of Tesla",
"age": 50
}
}
Now it would be more avro friendly of course to have customers lead to an array of the form
{
"customers": [
{
"customer_name": "paul_ince",
"name": "Mr Paul Ince",
"age": 54
},
{
...
}
]
}
But this would violate my constraint that the shape of the input data be unchanged.
This problem seems to manifest itself frequently if I rely on data from external sources or scrapes, or preexisting data that was never created for Avro.
In my head, the schema would look something like the below,
{
"fields": [
{
"name": "customers",
"type": {
"type": "record",
"name": "customers",
"fields": [
{
"name": $customer_name,
"type": {
"type": "record",
"name": $customer_name,
"fields": [
{
"name": "name",
"type": "string",
},
{
"name": "age",
"type": "int"
}
]
}
}
]
}
}
]
}
where $customer_name is an assignment value, defined on read. Just asking the question it feels like this violates fundamental avro but I must use Avro and I strongly desire to maintain the input shape of the data. It would be highly impractical to modify this, not least given how frequently this problem appears and how large and varied the data I need to transfer from JSON to Avro is
I have the following OpenAPI 3 schema:
{
...,
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"readOnly": true
},
"name": {
"type": "string"
}
}
},
"Report": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int64",
"readOnly": true
},
"user": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
Now, if I specify the GET requests for both User and Report everything looks good. The POST request for User is also working. However, the POST request for Report does not work. The body for the Report POST request should look like this:
{
"user": {
"id": 1
}
}
So the "name" property should not be specified since it is only a reference to a user that already exists and will be matched based on the id.
Is it possible to write the Report POST request so it understands that only the id of the user should be specified? Or am I forced to create two different Report schemas, one for the GET request and one for the POST request?
There are a couple ways you can approach this problem. You can either create a definition exclusively for POST, or split your User definition into more atomic components for reuse.
Option 1: Multiple Definitions
Construct your Report user definition to something like this:
"user": {
"id": {
"type": "integer",
"format": "int64",
"readOnly": true
}
}
This has the benefit of being quick and easy, with no impact on other areas of your defnition. But this lends itself to a lot of code duplication, and any future changes to your design will require you to make sure you don't miss any of these special definitions.
Option 2: Split and Reuse Your Definitions
You have a two distinct properties that have different uses, that are used in multiple definitions. This is a good candidate for a ref. Split up your User definition into multiple schemas. Something like this:
"schemas": {
"userId": {
"type": "integer",
"format": "int64",
"readOnly": true
},
"userName": {
"type": "string"
},
"User": {
"type": "object",
"properties": {
"id": {
"$ref": "#/components/schemas/userId"
},
"name": {
"$ref": "#/components/schemas/userName"
}
}
}
This allows you to reuse the userId in your Report with the same definition of what an id actually is. This approach can start getting hard to read as you start growing your definitions into a larger API, but is far more maintainable as your API changes shape over time. Note that this also helps to define the difference between a User ID and a Report ID, which, while sharing the same name, likely hold different data and may have divergent rules over time.
I'm building an OpenAPI (Swagger) 2.0 definition for the following XML payload to use within the Swagger UI:
<addressElement>
<key type="RECORD_ID" item="3">Enter value here</key>
</addressElement>
I'm having an issue figuring out how to display the default value 'Enter value here' for the element key. Where would one place this default value in an OpenAPI definition? My definition looks like this:
"definitions": {
"addressElement": {
"type": "object",
"title": "Address Element",
"properties": {
"key": {
"type": "object",
"properties": {
"type":{
"type": "string",
"example": "RECORD_ID",
"xml":{
"attribute": true
}
},
"item":{
"type": "integer",
"format": "int64",
"example": "3",
"xml":{
"attribute": true
}
}
}
},
},
"xml": {
"name": "addressElement"
}
}
}
This is currently not possible because OpenAPI does not have a way to represent XML elements with attributes such as
<key type="RECORD_ID" item="3">Enter value here</key>
Attributes can only be defined for objects
<obj attr="value">
<elem>Some text</elem>
</obj>
but not for simple <elem>text</elem> elements.
There's an open issue about this limitation here:
How to represent XML elements with attributes
That said, OpenAPI Specification maintainers are considering an option to use alternative data modeling schemas (such as XSD Schema), so your use case might be supported in a future version of OpenAPI.
We have some legacy file format, which I would need to migrate to Avro storage. The tricky part is that the records basically have
some common fields,
a discriminator field and
some unique fields, specific to the type selected by the discriminator field
all of them stored in the same file, without any order, fully mixed with each other. (It's legacy...)
In Java/object-oriented programming, one could represent our records concept as the following:
abstract class RecordWithCommonFields {
private Long commonField1;
private String commonField2;
...
}
class RecordTypeA extends RecordWithCommonFields {
private Integer specificToA1;
private String specificToA1;
...
}
class RecordTypeB extends RecordWithCommonFields {
private Boolean specificToB1;
private String specificToB1;
...
}
Imagine the data being something like this:
commonField1Value;commonField2Value,TYPE_IS_A,specificToA1Value,specificToA1Value
commonField1Value;commonField2Value,TYPE_IS_B,specificToB1Value,specificToB1Value
So I would like to process an incoming file and write its content to Avro format, somehow representing the different types of the records.
Can someone give me some ideas on how to achieve this?
Nandor from the Avro users email list was kind enough to help me out with this answer, credits go to him; this answer is for the record just in case someone else hits the same issue.
His solution is simple, basically using composition rather than inheritance, by introducing a common container class and a field referencing a specific subclass.
With this approach the mapping looks like this:
{
"namespace": "com.foobar",
"name": "UnionRecords",
"type": "array",
"items": {
"type": "record",
"name": "RecordWithCommonFields",
"fields": [
{"name": "commonField1", "type": "string"},
{"name": "commonField2", "type": "string"},
{"name": "subtype", "type": [
{
"type" : "record",
"name": "RecordTypeA",
"fields" : [
{"name": "integerSpecificToA1", "type": ["null", "long"] },
{"name": "stringSpecificToA1", "type": ["null", "string"]}
]
},
{
"type" : "record",
"name": "RecordTypeB",
"fields" : [
{"name": "booleanSpecificToB1", "type": ["null", "boolean"]},
{"name": "stringSpecificToB1", "type": ["null", "string"]}
]
}
]}
]
}
}
I'm working on an API which also generates swagger documentation. The issue is that for some reasons the request model/schema is not displayed in swagger UI but I don't get any error either.
I need to represent map to an array of strings . e.g. map[string][]string. Definition object definition is below.
{
"definitions": {
"versions": {
"type": "string",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
The support for maps is still not available in the UI - https://github.com/swagger-api/swagger-ui/issues/913.
You'd also want to change your definitions like this:
{
"definitions": {
"versions": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
To be clear, this defines a map where the values are arrays of strings.