I want to pass a custom resolver for enum type into my GraphQL server created using Flask and Ariadne.
In my schema.graphql file, I have defined an enum:
enum UtilizationScore {
ELEVATED
HIGH
NORMAL
}
And I want to assign values to each enum field like this:
utilization_score = EnumType(
"UtilizationScore", {
'ELEVATED': 20,
'HIGH': 30,
'NORMAL': 10
}, )
This is my GraphQL API:
#app.route("/graphql", methods=["POST"])
def graphql_server():
data = request.get_json()
print('GraphQL request: ', data)
success, result = graphql_sync(
schema,
data,
context_value=request,
debug=app.debug
)
print('Result from resolver: ', success, result)
status_code = 200 if success else 400
return jsonify(result), status_code
Now, I need to pass this utilization_score to my GraphQL server, which I have no idea how to do.
In the Ariadne documentation, I found this statement - (In my case, I have utilization_score instance instead of post_weight instance)
Include the post_weight instance in list of types passed to your GraphQL server, and it will automatically translate Enums between their GraphQL and Python values.
But I still couldn't figure out where to pass this enum resolver instance.
Related
In my flask server, a user passes a parameter to the server via a POST request, which symbolizes an entity in the server (a file, or a database entry).
If the id passed with the parameter, does not exist in the server, the server responds with:
return make_response(json.dumps({'error_message': 'item does not exist'}), 400)
How can i pass parameters in json.dumps()?
What i want to do is display: error_message: item XXXXXX does not exist
Where XXXXXX is the id that is passed as parameter to the server in the POST request.
For passing the parameter, one way you could do it is creating a formatted string, such as:
from flask import jsonify
value = # something
return make_response(jsonify("error message": "item {} does not exist".format(value)), 400)
Or you could do something like the following:
value = # something
data = {"error message": "item {} does not exist".format(value)}
return make_response(jsonify(data), 400)
And to note: use jsonify instead.
This function wraps dumps() to add a few enhancements that make life easier. It turns the JSON output into a Response object with the application/json mimetype.
The application/json in the request header and json string in the request body when I initiate an http request , the Odoo server receives the request, but the json returned to the client is not what I want to return.
Here are two additional key,jsonrpc,id,result.The dictionary corresponding to the key result is what I really want to return to the client.
And if I change the type variable in the http.route to http instead of json, I will can't receive json format data from the client.
What shoul I do?Thanks everyone!
My Odoo version is 10,python version is 2.7.12
Here is my code
controllers.py
from odoo.http import Controller,route
class API(Controller):
#route('/v1/access_something',type='json',auth='none',csrf=False,methods=['GET'])
def access_something(self,**kwargs):
return {"a":1,"b":2}
Test interface with requests
import requests
re = requests.get('http://192.168.1.55:8069/v1/access_something',json={"c":1},headers={'Content-Type':'application/json'})
print(re.json())
The data in re.json()
{
"jsonrpc": "2.0",
"id": null,
"result": {
"a": 1,
"b": 2
}
}
But the following result is what I want.
{
"a": 1,
"b": 2
}
I've found a way to solve this problem.
This problem arises because there is a method _json_responsein the source code JsonRequestthat we can overwrite dynamically.
In order not to interfere with the use of the original framework by others, we can pass our own specific parameters in our own decorator#http.routeby using kwargs. We construct the json dictionary we need to return to the client by determining whether the decorator has our own parameters.
Here is my codecontrollers.py
from odoo.http import Controller,route,JsonRequest
def _json_response(self, result=None, error=None):
lover = self.endpoint.routing.get('lover')
if lover == 'chun':
response = {}
if error is not None:
response['error'] = error
if result is not None:
response = result
else:
response = {
'jsonrpc': '2.0',
'id': self.jsonrequest.get('id')
}
if error is not None:
response['error'] = error
if result is not None:
response['result'] = result
if self.jsonp:
# If we use jsonp, that's mean we are called from another host
# Some browser (IE and Safari) do no allow third party cookies
# We need then to manage http sessions manually.
response['session_id'] = self.session.sid
mime = 'application/javascript'
body = "%s(%s);" % (self.jsonp, json.dumps(response),)
else:
mime = 'application/json'
body = json.dumps(response)
return Response(
body, headers=[('Content-Type', mime),
('Content-Length', len(body))])
setattr(JsonRequest,'_json_response',_json_response) #overwrite the method
class API(Controller):
#route('/v1/access_something',type='json',auth='none',csrf=False,methods=['GET'],lover='chun')
def access_something(self,**kwargs):
return {"a":1,"b":2}
The specific parameter lover='chun' is basis of our judgment.In method _json_response,we can get this parameter through self.endpoint.routing.get('lover')
I'm using Python Flask RestPlus framework, pretty new to Python. Trying to send back a response object along with some description and status code but failing with the following error:
TypeError: Object of type Response is not JSON serializable
This is what i am doing
from flask import jsonify, Response
from flask_restplus import Resource
class MyUsage(Resource):
def get(self):
# Do something
return "My Description" + jsonify(myObject), 200
I even tried sending the object like:
result = {'Desc': 'My Description',
'Result': jsonify(myObject)}
return result, 200
and
return jsonify('Desc': 'My Description',
'Result': myObject), 200
Everything failed with the same error.
jsonify will not serialize an object. It is used to convert a dictionary to a valid JSON response (there may be some exceptions to this).
There are a few ways to handle this. My personal favorite is with the marshmallow library because you can use it to deserialize request data into an object while also validating the data and for serializing your objects into a dictionary. This way your objects are never instantiated in an invalid state.
Another way that may be easier but less scalable, is writing a to_data method for your object.
class Object():
def __init__(self, a, b):
self.a = a
self.b = b
def to_data(self):
return {
'a': self.a,
'b', self.b
}
You can use this method to serialize your object.
myObject = Object(1,2)
data = myObject.to_data()
return jsonify(data), 200
just as #Kevin said,
jsonify will not serialize an object. It is used to convert a
dictionary to a valid JSON response (there may be some exceptions to
this).
I will provide another solution.
I notice that flask_restplus was used in your code, actually flask_restplus will do jsonfy automatically. The following source code is from flask_rest
def make_response(self, data, *args, **kwargs):
'''
Looks up the representation transformer for the requested media
type, invoking the transformer to create a response object. This
defaults to default_mediatype if no transformer is found for the
requested mediatype. If default_mediatype is None, a 406 Not
Acceptable response will be sent as per RFC 2616 section 14.1
:param data: Python object containing response data to be transformed
'''
default_mediatype = kwargs.pop('fallback_mediatype', None) or self.default_mediatype
mediatype = request.accept_mimetypes.best_match(
self.representations,
default=default_mediatype,
)
if mediatype is None:
raise NotAcceptable()
if mediatype in self.representations:
resp = self.representations[mediatype](data, *args, **kwargs)
resp.headers['Content-Type'] = mediatype
return resp
elif mediatype == 'text/plain':
resp = original_flask_make_response(str(data), *args, **kwargs)
resp.headers['Content-Type'] = 'text/plain'
return resp
else:
raise InternalServerError()
and the mediatype of self.representations is application/json, which means when media type of request is application/json, response will use representations['application/json'] function, to build up Response.
And that will call
def output_json(data, code, headers=None):
'''Makes a Flask response with a JSON encoded body'''
settings = current_app.config.get('RESTPLUS_JSON', {})
# If we're in debug mode, and the indent is not set, we set it to a
# reasonable value here. Note that this won't override any existing value
# that was set.
if current_app.debug:
settings.setdefault('indent', 4)
# always end the json dumps with a new line
# see https://github.com/mitsuhiko/flask/pull/1262
dumped = dumps(data, **settings) + "\n"
resp = make_response(dumped, code)
resp.headers.extend(headers or {})
return resp
With that said, you could setup RESTPLUS_JSON in your flask app.config
For exacmple, datetime is not a serializable object, therefore you could provide a convertor for that type as following code show.
First, you need to define a converter:
def datetime_json_converter(o):
if isinstance(o, datetime.datetime):
return o.__str__()
Then, you just need to set RESTPLUS_JSON in your flask app.config
app.config['RESTPLUS_JSON'] = {'default': datetime_json_converter}
One of the best solution is to use marshalling.
First you need to write a model, explaining what attributes from the object you want to use and what will be type of each attribute.
from flask_restplus import Resource, fields
model = api.model('Model', {
'name': fields.String,
'address': fields.String,
'date_updated': fields.DateTime(dt_format='rfc822'),
})
then you need to apply that on resource methods you want.
#api.route('/<id>')
class Todo(Resource):
#api.marshal_with(model) <-- Here you refer the model you created above
def get(self, id):
# find or prepare your object and just return that object
return object
I was trying to use flask as a backend for my iOs application. Currently it seems to be working, and the backend is hosted on heroku. The flask backend looks a little like this:
#app.route('/get_token', methods=['POST'])
def create_token():
token = make_token()
return token
I can run this function and confirm that it runs using a snippet like this with swift (using alamofire):
let url = "https://my-backend.herokuapp.com/get_token"
Alamofire.request(url, method: .post, parameters: nil, encoding: JSONEncoding.default)
And that runs fine. But now I want to do something (specifically save the token from flask) with the return value from flask. But I am confused as to how to do this. Any suggestions?
I would return a JSON response from Flask, and then you can easily parse that JSON object however you choose in your iOS app. Flask has a built in method, jsonify, which makes it easy to create a JSON responses.
You response would look like return jsonify(token=token)
Parse JSON with Alamofire:
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default)
.responseJSON { response in
print(response)
//to get status code
if let status = response.response?.statusCode {
switch(status){
case 201:
print("example success")
default:
print("error with response status: \(status)")
}
}
//to get JSON return value
if let result = response.result.value {
let JSON = result as! NSDictionary
print(JSON)
}
}
Source: https://stackoverflow.com/a/33022923/6685140
I'm trying to create simple Lambda function using Python 3.6.
The function should get a userId (my primary key in DynamoDB) in the request query string params and returns 200 if item exist in DB, here is my lambda function
import boto3
import os
from boto3.dynamodb.conditions import Key, Attr
def lambda_handler(event, context):
userId = event["userId"]
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['Customers'])
items = table.query(
KeyConditionExpression=Key('userId').eq(userId)
)
return items["Items"]
When i am doing tests in Lambda interface it works and return the correct user however, when trying from Postman or using API Gateway it returns the following error
{
"errorMessage": "'userId'",
"errorType": "KeyError",
"stackTrace": [
[
"/var/task/index.py",
7,
"lambda_handler",
"userId = event["userId"]"
]
]
}
What am i missing here ?
Struggling to understand "event" , documentation states its a python
dictionary but how can i print the result of it and actually debug the lambda
when called from Postman or API Gateway?
You are using event["userId"], this means that sending the request payload for example
GET API : api/users/
Request Body payload:
{
"userId":"1234"
}
then above code works, Suppose you want to send userId as path parameter
GET API :api/user/{userId}
then you can access in lambda function
userId = (event['pathparameters']['userId'])
better add the print statement
print(event) and check the logs in cloudwatch logs
This solved it for me on post requests
import json
def lambda_handler(event, context):
data = json.loads(event["body"])
email = data['email']
in case you are using the serverless framework you can also add the following code under your http event. but i dont think it is that necessary.
request:
parameters:
application/json: '{"email":"$input.params(''email'')"}'
Make sure you hadn't selected "Lambda Proxy" while creating the HTTP method. Proxy will not convert/modify the request and hence "event" will be null
In my case my Python Lambda required a key called exclude. To resolve the issue of getting this response when calling via API Gateway, I needed to update the integration request with a mapping template: