How to pass parameters using flask in array form - python

Using flask i am hitting the razorpay api in this way given below :
virtualAccUrl = 'https://'+str(current_app.config.get('RAZORPAY_ID'))+':'+str(
current_app.config.get('RAZORPAY_SECRET_ID'))+'#api.razorpay.com/v1/virtual_accounts'
virtual_payload = {
"receivers": {
"types": [
"qr_code"
],
"amount": 200,
"qr_code": {
"name": "Store_1",
"fixed_amount": 'true',
"payment_amount": 30000,
"customer_id": "CUS158022319",
"notes": {
"purpose": "Test UPI QR code notes"
}
},
"description": "Test UPI QR description",
"notes": {
"purpose": "Test UPI QR notes"
}
},
"amount_expected": 100
}
virtual_response = requests.post(url=virtualAccUrl, params=virtual_payload)
virtual_response = json.loads(virtual_response.content)
print('111111111111111')
print(virtual_response)
Biut it is returning me the error like :
{'error': {'code': 'BAD_REQUEST_ERROR', 'description': 'The receivers
must be an array.', 'source': 'business', 'step':
'payment_initiation', 'reason': 'input_validation_failed', 'metadata':
{}, 'field': 'receivers'}}
Can anyone please suggest me ?? how we can send the data using flask in api in array form . i am stuck here . i dont know how to solve this error . i am a newbe in flask thanks in advance.

As per the response "receivers" key's value must be an array whwereas you are passing dictionary. Try enclosing that value in list as
"receivers":[your_previous_value]
It would be better if you can share the api documentation you are reffering.

Related

Error in creation of work-item in Azure DevOps using Pytest/Python

I am trying to create a work-item using Python and requests library.
def test_create_work_item(work_items):
payload = {
'op': 'add',
'path': '/fields/System.Title',
'value': 'Sample bug'
}
pl = json.dumps(payload)
work_item = work_items.create(body=pl, type='bug')
assert work_item.status_code == 200
I am getting the below error for this :
{"$id":"1","innerException":null,"message":"You must pass a valid patch document in the body of the request.","typeName":"Microsoft.VisualStudio.Services.Common.VssPropertyValidationException,Microsoft.VisualStudio.Services.Common","typeKey":"VssPropertyValidationException","errorCode":0,"eventId":3000}
The same body works okay with Postman. So not sure what more is needed here to get it working.
I`m not familiar with Python.... Check this example: Create work item
The API uses an array of new fields:
[
{
"op": "add",
"path": "/fields/System.Title",
"from": null,
"value": "Sample task"
}
]
In your case, you use just one field in the request:
{
'op': 'add',
'path': '/fields/System.Title',
'value': 'Sample bug'
}

Eve: how to use different endpoints to access the same collection with different filters

I have an Eve app publishing a simple read-only (GET) interface. It is interfacing a MongoDB collection called centroids, which has documents like:
[
{
"name":"kachina chasmata",
"location":{
"type":"Point",
"coordinates":[-116.65,-32.6]
},
"body":"ariel"
},
{
"name":"hokusai",
"location":{
"type":"Point",
"coordinates":[16.65,57.84]
},
"body":"mercury"
},
{
"name":"cañas",
"location":{
"type":"Point",
"coordinates":[89.86,-31.188]
},
"body":"mars"
},
{
"name":"anseris cavus",
"location":{
"type":"Point",
"coordinates":[95.5,-29.708]
},
"body":"mars"
}
]
Currently, (Eve) settings declare a DOMAIN as follows:
crater = {
'hateoas': False,
'item_title': 'crater centroid',
'url': 'centroid/<regex("[\w]+"):body>/<regex("[\w ]+"):name>',
'datasource': {
'projection': {'name': 1, 'body': 1, 'location.coordinates': 1}
}
}
DOMAIN = {
'centroids': crater,
}
Which will successfully answer to requests of the form http://hostname/centroid/<body>/<name>. Inside MongoDB this represents a query like: db.centroids.find({body:<body>, name:<name>}).
What I would like to do also is to offer an endpoint for all the documents of a given body. I.e., a request to http://hostname/centroids/<body> would answer the list of all documents with body==<body>: db.centroids.find({body:<body>}).
How do I do that?
I gave a shot by including a list of rules to the DOMAIN key centroids (the name of the database collection) like below,
crater = {
...
}
body = {
'item_title': 'body craters',
'url': 'centroids/<regex("[\w]+"):body>'
}
DOMAIN = {
'centroids': [crater, body],
}
but didn't work...
AttributeError: 'list' object has no attribute 'setdefault'
Got it!
I was assuming the keys in the DOMAIN structure was directly related to the collection Eve was querying. That is true for the default settings, but it can be adjusted inside the resources datasource.
I figured that out while handling an analogous situation as that of the question: I wanted to have an endpoint hostname/bodies listing all the (unique) values for body in the centroids collection. To that, I needed to set an aggregation to it.
The following settings give me exactly that ;)
centroids = {
'item_title': 'centroid',
'url': 'centroid/<regex("[\w]+"):body>/<regex("[\w ]+"):name>',
'datasource': {
'source': 'centroids',
'projection': {'name': 1, 'body': 1, 'location.coordinates': 1}
}
}
bodies = {
'datasource': {
'source': 'centroids',
'aggregation': {
'pipeline': [
{"$group": {"_id": "$body"}},
]
},
}
}
DOMAIN = {
'centroids': centroids,
'bodies': bodies
}
The endpoint, for example, http://127.0.0.1:5000/centroid/mercury/hokusai give me the name, body, and coordinates of mercury/hokusai.
And the endpoint http://127.0.0.1:5000/bodies, the list of unique values for body in centroids.
Beautiful. Thumbs up to Eve!

Flask-restplus returning marshal model instead of the data

So I'm pretty new to implementing flask-restplus and I have encountered this road block.
I have read the restplus docs over and over again and followed several exampled. But the behavior that I'm facing is very much different from what is supposed to be.
So I have a model that is supposed to be a list of objects of another model (returned from the function drone_model()).
drones_list = api.model('drones_list', {
'items': fields.List(fields.Nested(drone_model())),
'message':fields.String(''),
'code': fields.Integer('')
})
Everything works fine, no errors. But when I try the API (http://127.0.0.1:5000/datamine/v2/drones), as a response I get the Marshalling model back instead of the data itself. If I print the data, it gets printed, but for some reason in the web, the restplus model is returned.
Below I have the code that I had written. If I take the marshal_with decorator off, then the data is returned just fine.
#api.route('/')
class DronesList(Resource):
#api.marshal_with(drones_list, envelope='data')
#api.response(200, 'All drones successfully fetched!')
def get(self):
"""
Get all drones!.
"""
from app.utils.common import get_start_end_date_from_request
start_date, end_date = get_start_end_date_from_request(request)
drones = []
for drone in Drone.objects:
drones.append({
'id': str(drone.id),
'serial_id': drone.serial_id,
'maintenances': [],
'status': get_dynamic_status(drone, start_date, end_date),
'picture_url': drone.asset.picture_url,
'manufacturer': drone.asset.manufacturer,
'model_name': drone.asset.model_name,
'drone_type': drone.asset.drone_type,
'payload_type': drone.asset.payload_type,
'asset_url': drone.get_url(drone.id)
})
success = ClientSuccessFunctionClass('All drones successfully fetched!', 200, drones)
return (success.to_dict())
These are the outputs on the browser:
1. Without the marshal decorator:
{
"data": {
"items": [
{
"id": "5aeafcb93a33683f73827e91",
"serial_id": "Drone 1",
"maintenances": [],
"status": "Decommissioned",
"picture_url": "some img url",
"manufacturer": "DJI",
"model_name": "Phantom 4 Pro",
"drone_type": "Quadcopter",
"payload_type": "RGB Camera",
"asset_url": "http://127.0.0.1:5000/datamine/v1/drones/5aeafcb93a33683f73827e91"
},
{
"id": "5aeaff374f85747f90df2714",
"serial_id": "Drone 2",
"maintenances": [],
"status": "Available",
"picture_url": "sime url",
"manufacturer": "DJI",
"model_name": "Phantom 4",
"drone_type": "Quadcopter",
"payload_type": "RGB Camera",
"asset_url": "http://127.0.0.1:5000/datamine/v1/drones/5aeaff374f85747f90df2714"
}
],
"message": "All drones successfully fetched!",
"code":200
}
}
2. With the marshal decorator:
{
"data": {
"items": [
{
"id": "Id of Drone",
"serial_id": "Name of Drone",
"status": "Status of Drone",
"maintenances": null,
"picture_url": "Picture URL",
"manufacturer": "Manufacturer of Drone",
"model_name": "Model name of Drone",
"drone_type": "Type of Drone",
"payload_type": "Payload type of Drone",
"asset_url": "Asset URL of Drone"
}
],
"message": "",
"code": ""
}
}
It would be really helpful if someone could tell me what I'm doing wrong as I need to recive the output as the one shown in snippet of the output without the decorator.
Thank you.
Here is a diagram showing invocation order from top to bottom to help make sense of what is happening:
get()
→ api.response(200, 'All drones successfully fetched!') # documents the response
→ api.marshal_with(drones_list, envelope='data')` # returns marshalled dict
The result from invoking get is passed to the api.response decorator function whose result is passed on to api.marshal_with decorator function.
Looking at the shape of the dictionary returned from invoking get()
{
data {
items [
{
id,
serial_id,
maintenances,
status,
picture_url,
manufacturer,
model_name,
drone_type,
payload_type,
asset_url
}
],
message,
code
}
}
The message and code in the response are nested inside of the data.
You need to model the data appropriately, to be able to marshal it. This can be done by passing an argument for what field to look up in the marshal dictionary.
drones_list = api.model('drones_list', {
'items': fields.List(fields.Nested(drone_model()), attribute='data.items'),
'message':fields.String(attribute='data.message'),
'code': fields.Integer(attribute='data.code')
})
As you can see, it's pretty redundant applying the api.marshal_with decorator function on the view given that it's only unnests then nests the result in data field.

scan python helper in elasticsearch with slice

I have the following code:
client = Elasticsearch(hosts=['host'], port=9200)
scan_arguments = {'query': {'slice': {'max': 1, 'id': 0}}, 'preference': '_shards:0', 'index': u'my_index'}
for hit in scan(client, **scan_args):
# do something with hit
and I get the following error
RequestError: TransportError(400, u'parsing_exception', u'[slice] failed to parse field [max]')
How should the slice parameter be passed in the scan function?
"max" needs to be >1 in my experience. I saw the same error before when using "max":1.
The raw error from the HTTP API says max must be greater than 1.
{
"error": {
"root_cause": [
{
"type": "x_content_parse_exception",
"reason": "[3:20] [slice] failed to parse field [max]"
}
],
"type": "x_content_parse_exception",
"reason": "[3:20] [slice] failed to parse field [max]",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "max must be greater than 1"
}
},
"status": 400
}

Python Falcon filtering through URL

I have a small API that i'm working on, everything works ok, all my requests do what they are supposed to but when I try to filter results through the URL query for some reason it works for id but not for device field.
def on_get(self, req, resp):
"""Handles GET requests"""
if req.get_param("id"):
result = {'location': r.db(PROJECT_DB).table(PROJECT_TABLE).get(req.get_param("id")).run(db_connection)}
elif req.get_param("device"):
result = {'location': r.db(PROJECT_DB).table(PROJECT_TABLE).get(req.get_param("device")).run(db_connection)}
else:
location = r.db(PROJECT_DB).table(PROJECT_TABLE).run(db_connection)
result = {'locations': [i for i in location]}
resp.body = json.dumps(result)
example http://localhost:8000/location?id=(some random id) this will work
but if i do http://localhost:8000/location?device=(some device) this will not work, returns null
So could anyone tell me what am I doing wrong? or better yet if anyone knows a better way to filter using the URL?
Note: I am using rethinkdb
EDIT:
This is what I have normally:
{
"locations": [
{
"id": "4bf4b94f-747a-42db-9d54-a8399d995025",
"location": "gps coords",
"device": "Device 2"
},
{
"id": "b5cce561-37d2-42e7-86e4-a31c008b0af2",
"location": "gps coords",
"device": "Device 1"
},
{
"id": "bebba7cf-710c-4ee8-ad69-2d58174d4e02",
"location": "gps coords",
"device": "Device 1"
},
{
"id": "e928f84b-60ff-40f3-b839-920bc99e5480",
"location": "gps coords",
"device": "Device1"
}
]
}
Filtering by id works ok, but not by device which is weird
I found the answer to this problem, the reason why it did not war was because rethinkdb only gets via primary key on the get query
result = {'location': r.db(PROJECT_DB).table(PROJECT_TABLE).get(req.get_param("device")).run(db_connection)}
so what I should have done was to filter the results by what I wanted like this and it would have worked
result = {'location': list(r.db(PROJECT_DB).table(PROJECT_TABLE).filter({'device': param}).run(db_connection))}
Thanks for the help everyone and hope this answer helps.

Categories