"lists of Submodels" in Fastapi - 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.

Related

How to filter google calendar REST API events by attendee's email

I'm accessing Google Calendar REST API for Calendar Events, trying to figure out a proper notation for q parameter, to filter all events where one of the attendees is identified by email (let's say foo#bar.com)
I've tried: q=attendee.email:foo#bar.com, q=attendee.email=foo#bar.com, q=attendees.email=foo#bar.com, q=attendees.email="foo#bar.com"...
but with no results (empty list, once the q parameter is filled in)
Is it supported at all?
Is there a list of valid q parameter fields to filter by?
You cannot use any Calendar API call to directly search for attendees.
However, you can achieve this by code. You have to list all the events, loop through them and filter the events if the email you wrote coincides with the email in the attendees. For example:
function searchEvents() {
var calendarId = "primary";
var email = "test#email.com";
var result = Calendar.Events.list(calendarId).items;
for (var i = 0; i < result.length; i++){
if (result[i].attendees != undefined){ //Filters out the events without attendees
for (var j = 0; j < result[i].attendees.length; j++){
if (result[i].attendees[j].email == email){
Logger.log(result[i]); //It returns all the event information
}
}
}
}
}
The full resource object returned:
{
"kind": "calendar#calendarListEntry",
"etag": etag,
"id": string,
"summary": string,
"description": string,
"location": string,
"timeZone": string,
"summaryOverride": string,
"colorId": string,
"backgroundColor": string,
"foregroundColor": string,
"hidden": boolean,
"selected": boolean,
"accessRole": string,
"defaultReminders": [
{
"method": string,
"minutes": integer
}
],
"notificationSettings": {
"notifications": [
{
"type": string,
"method": string
}
]
},
"primary": boolean,
"deleted": boolean,
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
string
]
}
}
REFERENCES:
Events List
List Resource
The "q" parameter is working like a text search in event list.
Free text search terms to find events that match these terms in the
following fields: summary, description, location, attendee's
displayName, attendee's email. Optional.
It possible to search events with specified email:
calendar.events.list(
{
q: 'attendee#email.test',
calendarId: 'primary',
timeMin: new Date().toISOString(),
maxResults: 10,
singleEvents: true,
orderBy: 'startTime',
}
It should return events where 'attendee#email.test' is specified

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.

API Gateway and DynamoDB PutItem for String Set

I can't seem to find how to correctly call PutItem for a StringSet in DynamoDB through API Gateway. If I call it like I would for a List of Maps, then I get objects returned. Example data is below.
{
"eventId": "Lorem",
"eventName": "Lorem",
"companies": [
{
"companyId": "Lorem",
"companyName": "Lorem"
}
],
"eventTags": [
"Lorem",
"Lorem"
]
}
And my example template call for companies:
"companies" : {
"L": [
#foreach($elem in $inputRoot.companies) {
"M": {
"companyId": {
"S": "$elem.companyId"
},
"companyName": {
"S": "$elem.companyName"
}
}
} #if($foreach.hasNext),#end
#end
]
}
I've tried to call it with String Set listed, but it errors out still and tells me that "Start of structure or map found where not expected" or that serialization failed.
"eventTags" : {
"SS": [
#foreach($elem in $inputRoot.eventTags) {
"S":"$elem"
} #if($foreach.hasNext),#end
#end
]
}
What is the proper way to call PutItem for converting an array of strings to a String Set?
If you are using JavaScript AWS SDK, you can use document client API (docClient.createSet) to store the SET data type.
docClient.createSet - converts the array into SET data type
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName:table,
Item:{
"yearkey": year,
"title": title
"product" : docClient.createSet(['milk','veg'])
}
};

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"
]
}

ExtJS4 - Reconfiguring a grid in ASP.NET - JSON structure issue

One of ASP.NET's security features is proving to be a mountain to scale here - the "d" property addition when returning a JSON response appears to be confusing ExtJS when I attempt to reconfigure a gridpanel dynamically, causing it to fail when attempting to generate new column structure.
I followed this solution by nicholasnet:
http://www.sencha.com/forum/showthread.php?179861-Dynamic-grid-columns-store-fields
and it works beautifully, until the JSON payload is wrapped around the "d" property, e.g.
{"d":{
"metaData": {
"root": "data",
"fields": [{
"type": "int",
"name": "id",
"hidden": true,
"header": "id",
"groupable": false,
"dataIndex": "id"
}, ...omitted for brevity...]
},
"success": true,
"data": [{
"id": "1",
"controller": "Permissions",
"description": "Allow to see permission by roles",
"administrator": true,
"marketing": false
}]
}
}
I can't work out how to tell ExtJS to skirt around this problem. I've tried setting the "root" property of the AJAX reader to "d.data" but that results in the grid showing the correct number of rows but no data at all.
I've all the property descriptors required for column metadata ("name", "header", "dataIndex") in the JSON so I don't believe the JSON structure to be the cause. My main lead at the moment is that on the event handler:
store.on
({
'load' :
{
fn: function(store, records, success, operation, eOpts)
{
grid.reconfigure(store,store.proxy.reader.fields);
},
scope: this
}
}, this);
The fields in historyStore.proxy.reader.fields part is undefined when I pass the "d"-wrapped JSON. Anyone have any ideas on why this is or how to solve this issue?
edit: my Store/proxy
Ext.define('pr.store.Store-History', {
extend: 'Ext.data.Store',
model: 'pr.model.Model-History',
proxy: {
type: 'ajax',
url: '/data/history.json',
reader: {
type: 'json',
root: 'd'
}
}
});
Ext.define('pr.store.Store-History', {
extend: 'Ext.data.Store',
model: 'pr.model.Model-History',
proxy: {
type: 'ajax',
url: '/data/history.json',
reader: {
type: 'json',
root: 'data',
readRecords: function(data) {
//this has to be before the call to super because we use the meta data in the superclass readRecords
var rootNode = this.getRoot(data);
if (rootNode.metaData) {
this.onMetaChange(rootNode.metaData); // data used to update fields
}
/**
* #deprecated will be removed in Ext JS 5.0. This is just a copy of this.rawData - use that instead
* #property {Object} jsonData
*/
this.jsonData = rootNode;
return this.callParent([rootNode]); // data used to get root element and then get data from it
},
}
}
});
Update:
you are not getting fields in reader because the default code for getting fields from data doesn't handle your wrapped data, so you need to change 'readRecords' function to handle your custom data

Resources