Swagger Documentation with flask_apispec = array of objects - flask-restful

so I'm having an annoying problem with my flask_apispec documenter.
I want the post body of my api to receive this in
kwargs:
[
{
"CreatedUserGuid": "string",
"DeviceGuid": "string",
"DeviceMetaDataGuid": "string",
"LastModifiedUserGuid": "string",
"MetaDataTypeId": "string",
"MetadataFieldGroupGuid": "string",
"MetadataFieldName": "string",
"MetadataFieldTemplateMapGuid": "string",
"MetadataFieldValue": "string"
}
]
Note: flat array as bulk input is what I want.
in the swagger.json it would look like this: ( I want to achieve this through the flask_restful and flask_apispec auto documenting)
"DMDNEsted" : {
"type":"object",
"properties": {
"PartyMetaData": {
"type":"array",
"items": {
"$ref":"#/components/schemas/DMDSearch"
}
}
}
},
but I cant seem to achieve this .... Using below code (see bottom of screen) I obviously get this in swags:
The code at present is:
class DMDSearch(Schema):
CreatedUserGuid= fields.String(required=False)
DeviceGuid= fields.String(required=False)
DeviceMetaDataGuid= fields.String(required=False)
LastModifiedUserGuid= fields.String(required=False)
MetaDataTypeId= fields.String(required=False)
MetadataFieldGroupGuid = fields.String(required=False)
MetadataFieldName= fields.String(required=False)
MetadataFieldTemplateMapGuid= fields.String(required=False)
MetadataFieldValue= fields.String(required=False)
class DMDNEsted(Schema):
deviceMetadata = fields.Nested(DMDSearch, many=True)
class DeviceMetaDataApi(MethodResource,Resource):
#doc(description='Manage Device Meta Data',tags=['Device Linking','Device Management'],
#use_kwargs(DMDNEsted, location=('json'))
#marshal_with(DeviceMetaDataSchemaAll)
def post(self,**kwargs):
#blah blah handle post

Related

"lists of Submodels" in Fastapi

How can I get the key and value in the list of submodel?
Below is the code that I made,
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
price: float
tax: list[float]
image: list[Image]
#app.post("/items")
def update_item(item: Item):
return item.image
Send data as a request body
{
"name": "item_name",
"price": 120.99,
"tax": [
1.99, 2.99
],
"image": [
{
"url": "www.naver.com",
"name": "naver"
},
{
"url": "www.google.com",
"name": "google"
}
]
}
And I can send the response as below.
[
{
"url": "www.stackoverflow.com",
"name": "stackoverflow"
},
{
"url": "www.google.com",
"name": "google"
}
]
How to get the key(`"url") and value("google") from the List of Image model?
I newly start to learn fastapi, and I thought that I can get the values in the list of Image model through item.image.url or something like that, likewise item.name or item.tax, but it didn't work.
To explain the problem in more detail, I would like to check there is a value google in Image model first, and if it exists then get the value of url key.
I tried as below,
#app.post("/items")
def update_item(item: Item):
url = [i['url'] for i in item.image if i['name'] == 'naver']
return url
but it returns
TypeError: 'Image' object is not subscriptable
You used i['url'] which is how you would approach a dictionary. However, this is a pydantic model, with properties. You were quite close, but you should replace i['url'] with i.url (and also i.name a little further in your code). So, like this:
#app.post("/items")
def update_item(item: Item):
url = [i.url for i in item.image if i.name == 'naver']
if len(url) == 1:
return url[0]
return None
Note that variable url a list, you should check if the list is empty or not before trying to get the first element (which would be the URL of the image named 'never'). The above would return None if no Images with name 'naver' is found.

Postman Schema Validation using TV4

I'm having trouble validating a schema in Postman using tv4 inside the tests tab - it is always returning a true test, no matter what I feed it. I am at a complete loss and could really use a hand - here is my example JSON Response, and my tests:
I've tried a ton of variations from every Stack Overflow/tutorial I could find and nothing will work - it always returns true.
//Test Example
var jsonData = JSON.parse(responseBody);
const schema = {
"required" : ["categories"],
"properties": {
"categories": {
"required" : ["aStringOne", "aStringTwo", "aStringThree" ],
"type": "array",
"properties" : {
"aStringOne": {"type": "string" },
"aStringTwo": {"type": "null" },
"aStringThree": {"type": "boolean" }
}
}
}
};
pm.test('Schema is present and accurate', () => {
var result=tv4.validateMultiple(jsonData, schema);
console.log(result);
pm.expect(result.valid).to.be.true;
});
//Response Example
{
"categories": [
{
"aStringOne": "31000",
"aStringTwo": "Yarp",
"aStringThree": "More Yarp Indeed"
}
]
}
This should return false, as all three properties are strings but its passing. I'm willing to use a different validator or another technique as long as I can export it as a postman collection to use with newman in my CI/CD process. I look forward to any help you can give.
I would suggest moving away from using tv4 in Postman, the project isn't actively supported and Postman now includes a better (in my opinion), more actively maintained option called Ajv.
The syntax is slightly different but hopefully, this gives you an idea of how it could work for you.
I've mocked out your data and just added everything into the Tests tab - If you change the jsonData variable to pm.response.json() it will run against the actual response body.
var jsonData = {
"categories": [
{
"aStringOne": "31000",
"aStringTwo": "Yarp",
"aStringThree": "More Yarp Indeed"
}
]
}
var Ajv = require('ajv'),
ajv = new Ajv({logger: console, allErrors: true}),
schema = {
"type": "object",
"required": [ "categories"],
"properties": {
"categories": {
"type": "array",
"items": {
"type": "object",
"required": [ "aStringOne", "aStringTwo", "aStringThree" ],
"properties": {
"aStringOne": { "type": "string" },
"aStringTwo": { "type": "integer"},
"aStringThree": { "type": "boolean"},
}
}
}
}
}
pm.test('Schema is valid', function() {
pm.expect(ajv.validate(schema, jsonData), JSON.stringify(ajv.errors)).to.be.true
});
This is an example of it failing, I've included the allErrors flag so that it will return all the errors rather than just the first one it sees. In the pm.expect() method, I've added JSON.stringify(ajv.errors) so you can see the error in the Test Result tab. It's a little bit messy and could be tidied up but all the error information is there.
Setting the properties to string show the validation passing:
If one of the required Keys is not there, it will also error for this too:
Working with schemas is quite difficult and it's not easy to both create them (nested arrays and objects are tricky) and ensure they are doing what you want to do.
There are occasions where I thought something should fail and it passed the validation test. It just takes a bit of learning/practising and once you understand the schema structures, they can become extremely useful.

ASP.Net Core - Get All data of a post form

I want to save all data of a form.
My form has these elements-
( Using Postman Plugin )
My controller is like this-
[HttpPost]
public async Task<IActionResult> Insert(IFormCollection data)
{
return Ok(data);
}
So, I am getting something like this-
[
{
"key": "user_id",
"value": [
"'12'"
]
},
{
"key": "title",
"value": [
"123"
]
},
{
"key": "text[]",
"value": [
"werwer",
"ghj"
]
}
]
I want to get the value of texts.
So, for this case-
"werwer",
"ghj"
So, I have tried something like this-
foreach (string description in data["text"])
{
// description => empty
}
and also tried this-
data.text
and also-
data->text
But nothing works for me.
Can anyone please help?
Thanks in advance for helping.
Why not loop through each keys and if the key is "text", get the values. Since the value is a comma seperated string, you can call the Split method on that to get an array which contains 2 items( from your sample input).
foreach (string description in data.Keys)
{
if (description.Equals("text"))
{
var v = data[description];
var stringItems = v.Split(',');
foreach (var stringItem in stringItems)
{
//do something with stringItem
}
}
}
BTW, the key should be text, not text[]. Even if you have muliple input fields with the same name "text", when you submit, It will be a single key ("text") with 2 items int he value property
{
"key": "text",
"value": [
"werwer",
"ghj"
]
}

Newtonsoft.Json.Schema.Generation: Human readable 'definitions' section

I want to have definitions section better generated and organized and for me this would mean to not allow depth building up in definitions, but, each class involved in the structure tree should have its own entry in the definitions section and referenced via $ref. This means that for each definition I would only have a list of properties that would either be of primitive types (string, boolean, etc.) or would be a $ref to another definition entry for another custom class. You can also see this as depth 1 definition, close to how classes are originally defined in C#.
To illustrate this via a trivial example:
JSchemaGenerator schemaGenerator = new JSchemaGenerator();
schemaGenerator = new JSchemaGenerator()
{
DefaultRequired = Newtonsoft.Json.Required.DisallowNull,
SchemaIdGenerationHandling = SchemaIdGenerationHandling.TypeName,
SchemaLocationHandling = SchemaLocationHandling.Definitions,
SchemaReferenceHandling = SchemaReferenceHandling.Objects,
};
JSchema schema = schemaGenerator.Generate(typeof(Setting));
Renders:
{
"id": "Setting",
"definitions": {
"SubSetting": {
"id": "SubSetting",
"type": "object",
"properties": {
"SubSubSetting": {
"id": "SubSubSetting",
"type": "object",
"properties": {
"String": {
"type": "string"
}
}
}
}
},
"SubSubSetting": {
"$ref": "SubSubSetting"
}
},
"type": "object",
"properties": {
"SubSetting": {
"$ref": "SubSetting"
},
"SubSubSetting": {
"$ref": "SubSubSetting"
}
}
}
Thus, SubSubSetting definition is placed inline SubSetting definition and later we have SubSubSetting defined as reference to that inline definition. That's what I want to avoid as for complex data structures it becomes really obscure and I want to provide the schema even as part of a living, auto-generated documentation based on data annotations and JsonProperty.
How can I accomplish this using JSchemaGenerator?
Maybe I shouldn't do this, but as a second very short question: Are those $ref syntactically correct? Shouldn't they look like "#/definitions/SubSetting"?
The latest version of Json.NET Schema (3.0.3) has been updated to fix this issue. SubSubSetting will contain the full definition and not just a $ref.
https://github.com/JamesNK/Newtonsoft.Json.Schema/releases/tag/3.0.3

Build a Map from a Set in Groovy

We have the following legacy data structure of Parent and Child objects of the same type
Parent1(name1,code1,null)
Child11(name11,code11,Parent1)
Child12(name12,code12,Parent1)
Parent2(name2,code2,null)
Child21(name21,code21,Parent2)
Child22(name22,code22,Parent2)
etc.
We have a legacy service available that returns a Set of all the Child objects. The Parent objects are not returned but we can call a getParent() getter for a particular Child in the Set to get its Parent. We need to call this service from a Groovy class, and afterwards build a Map that reflects the original structure
def dataMap = [data:[["name":"name1", "code":"code1",
"children":[["name":"name11", "code":"code11"],
["name":"name12", "code":"code12"]]],
["name":"name2", "code":"code2",
"children":[["name":"name21", "code":"code21"],
["name":"name22", "code":"code22"]]]]]
So basically the Map keys are the Parent (name,code) pairs, and the values are Lists of the respective Child objects' (name,code) pairs (the Map will be rendered to JSON afterwards actually)
Being quite novice to Groovy I could probably solve this using Java syntax, but I wonder whether there is a more concise solution using Groovy specific features? Any ideas are appreciated
So as I understand it, this is the setup you have:
import groovy.transform.*
import groovy.json.*
#TupleConstructor(includeFields=true)
class Node {
String name
String code
private Node parent
String getParentName() { parent?.name }
String getParentCode() { parent?.code }
}
def parent1 = new Node( 'name1', 'code1', null )
def child11 = new Node( 'name11', 'code11', parent1 )
def child12 = new Node( 'name12', 'code12', parent1 )
def parent2 = new Node( 'name2', 'code2', null )
def child21 = new Node( 'name21', 'code21', parent2 )
def child22 = new Node( 'name22', 'code22', parent2 )
// This is returned by a call to your API
Set nodes = [ child11, child12, child21, child22 ]
Then, you can do the following (there are probably other routes, and this will only work for single depth trees)
// Get a set of parent nodes
Set parents = nodes.collect { [ name:it.parentName, code:it.parentCode ] }
// Utility closure to return a name and code in a Map
def format = { Node n ->
[ name: n.name, code: n.code ]
}
// Collect the formatted parents with their formatted children into a Map
def dataMap = [ data:parents.collect { p ->
p + [ children:nodes.findAll {
it.parentName == p.name && it.parentCode == p.code
}.collect { format( it ) } ]
} ]
// Print the JSON representation of this
println new JsonBuilder( dataMap ).toPrettyString()
That should print:
{
"data": [
{
"name": "name2",
"code": "code2",
"children": [
{
"name": "name21",
"code": "code21"
},
{
"name": "name22",
"code": "code22"
}
]
},
{
"name": "name1",
"code": "code1",
"children": [
{
"name": "name11",
"code": "code11"
},
{
"name": "name12",
"code": "code12"
}
]
}
]
}

Resources