What is the proper way to handle response classes in Flask-RESTplus?
I am experimenting with a simple GET request seen below:
i_throughput = api.model('Throughput', {
'date': fields.String,
'value': fields.String
})
i_server = api.model('Server', {
'sessionId': fields.String,
'throughput': fields.Nested(i_throughput)
})
#api.route('/servers')
class Server(Resource):
#api.marshal_with(i_server)
def get(self):
servers = mongo.db.servers.find()
data = []
for x in servers:
data.append(x)
return data
I want to return my data in as part of a response object that looks like this:
{
status: // some boolean value
message: // some custom response message
error: // if there is an error store it here
trace: // if there is some stack trace dump throw it in here
data: // what was retrieved from DB
}
I am new to Python in general and new to Flask/Flask-RESTplus. There is a lot of tutorials out there and information. One of my biggest problems is that I'm not sure what to exactly search for to get the information I need. Also how does this work with marshalling? If anyone can post good documentation or examples of excellent API's, it would be greatly appreciated.
https://blog.miguelgrinberg.com/post/customizing-the-flask-response-class
from flask import Flask, Response, jsonify
app = Flask(__name__)
class CustomResponse(Response):
#classmethod
def force_type(cls, rv, environ=None):
if isinstance(rv, dict):
rv = jsonify(rv)
return super(MyResponse, cls).force_type(rv, environ)
app.response_class = CustomResponse
#app.route('/hello', methods=['GET', 'POST'])
def hello():
return {'status': 200, 'message': 'custom_message',
'error': 'error_message', 'trace': 'trace_message',
'data': 'input_data'}
result
import requests
response = requests.get('http://localhost:5000/hello')
print(response.text)
{
"data": "input_data",
"error": "error_message",
"message": "custom_message",
"status": 200,
"trace": "trace_message"
}
Related
I want to pass an array of JSON object to flask.
My data looks like :
{
"business_code": "U001",
"cust_number": 200769623,
"clear_date": "2020-02-11",
"buisness_year": "2020-01-01",
"doc_id": "1930438491",
"posting_date": "2020-01-26",
"document_create_date": "2020-01-25",
"document_create_date1": "2020-01-26",
"due_in_date": "2020-02-10",
"invoice_currency": "USD",
"document_type": "RV",
"posting_id": 1,
"area_business": "",
"total_open_amount": 54273.28,
"baseline_create_date": "2020-01-26",
"cust_payment_terms": "NAH4",
"invoice_id": 1930438491,
"isOpen": 0,
"aging_bucket": null,
"is_deleted": 0
}
I tried it by passing the values in URL by modifying the flask code but my company doesn't want flask code to be modified.
I want to pass the data to this and then in return want to receive the response back to my react js application.
My flask code looks like :
#app.route("/get_prediction", methods=["GET",'POST'])
def get_prediction():
if request.method == "POST":
doc_id_list = list(request.json["data"])
print(doc_id_list)
response = make_response(jsonify(New_Bucket.doc_id_bucket(doc_id_list)),200)
response.headers["Access-Control-Allow-Origin"]="*"
response.headers["Content-Type"] = "application/json"
return response
I don't really get how I can accomplish this.
Upon trying to test the JSON payload to a PUT request, I'm getting the following error. I'm not sure if its my test that's causing the error or if there is something else that is causing the issue? If I comment out that line the HTTP verb responds with no error.
werkzeug.exceptions.BadRequest:
400 Bad Request: Failed to decode JSON object: Expecting value: line 1 column 1 (char 0)
-> args = self.put_request_parser.parse_args()
Upon debugging, here what is actually being sent when parse_args() is invoked. I'm not sure why unparsed_arguments is an empty dictionary in this case?
EnvironHeaders([('User-Agent', 'werkzeug/0.14.1'), ('Host', 'localhost'),
('Content-Type', 'application/json'), ('Content-Length', '0'),
('Authorization', 'Bearer <token>')]),
'url': 'http://localhost/api/v1/todos/3', 'unparsed_arguments': {}}
tests.py
class TestUpdateTodoResource(ApiTestCase):
'''Verify that a client succesfully updates an existing todo.'''
def test_put_update_user_todo(self):
with app.test_client() as client:
http_response = client.put(
"api/v1/todos/3",
headers={
'content-type': 'application/json',
'authorization': f"Bearer {token}"
},
data = {
"name": "Never do this todo!"
}
)
self.assertEqual(http_response.status_code, 204)
todos.py
class ApiTodo(Resource):
put_request_parser = reqparse.RequestParser()
put_request_parser.add_argument(
'name',
required=True,
location=['form', 'json'],
help="Cannot accept a blank description"
)
#auth.login_required
def put(self, id):
try:
user_todo = Todo.select().join(User).where(
(Todo.id == id) & (User.id == g.user.id)
).get()
except Todo.DoesNotExist:
abort(404, description="That todo no longer exists")
args = self.put_request_parser.parse_args()
if not args['name']:
abort(400, description="Must provide a todo description")
updated_todo = user_todo.update(**args)
updated_todo.execute()
return marshal(set_todo_creator(updated_todo), todo_fields, 'todo'), 204
I want to use this route here (below) and render my react file. Using a python route.... Could someone give me some direction on how I can accomplish this?
#Auth.route('/login', methods=['GET'])
def login():
#data = {'username':'bob', 'password':'peepee123'}
#session['token'] = 'jsdkfkj934ujeklfjdlndsflds'
auth = request.authorization
if auth and auth.password == 'password':
token = jwt.encode({'user': auth.username}, app.config['SECRET_KEY'])
return jsonfiy({'token': token.decode('UTF-8')})
return make_response('Could Not verify!', 401, {'WWW-Authenticate': 'Basic realm = "Login Required"'})
If you want to render react in server site in python you can use python-react-v8, but you need to have the same react tree in server and client or it wont work, checkout hydrate in docs. For that you need to have working react app.
Example of usage:
import react
# setup react
react.set_up() # Initialize V8 machinery
react.utils.load_libs(['./bundle.js'])
#Auth.route('/login', methods=['GET'])
def login():
#data = {'username':'bob', 'password':'peepee123'}
#session['token'] = 'jsdkfkj934ujeklfjdlndsflds'
auth = request.authorization
if auth and auth.password == 'password':
token = jwt.encode({'user': auth.username}, app.config['SECRET_KEY'])
data = {'token': token.decode('UTF-8')};
react_ = react.React({
'url': request.get_full_url(),
'data': data
})
context = {
'content': react_.render(),
'data': react_.to_json(data)}
return render('index.html', context);
data = {'token': null, 'reason': "Login Required"}
react_ = react.React({
'url': request.get_full_url(),
'data': data
})
context = {
'content': react_.render(),
'data': react_.to_json(data)
}
return render('index.html', context);
I have a problem coding a bot in Python that works with the new inline mode.
The bot gets the query, and while trying to answer, it receives error 400.
Here is a sample of data sent by the bot at this time:
{
'inline_query_id': '287878416582808857',
'results': [
{
'type': 'article',
'title': 'Convertion',
'parse_mode': 'Markdown',
'id': '287878416582808857/0',
'message_text': 'blah blah'
}
]
}
I use requests library in to make requests, and here is the line that does it in the code:
requests.post(url = "https://api.telegram.org/bot%s%s" % (telegram_bot_token, "/answerInlineQuery"), data = myData)
With myData holding the data described in the sample.
Can you help me solve this, please?
I suspect it is because you haven't JSON-serialized the results parameter.
import json
results = [{'type': 'article',
'title': 'Convertion',
'parse_mode': 'Markdown',
'id': '287878416582808857/0',
'message_text': 'blah blah'}]
my_data = {
'inline_query_id': '287878416582808857',
'results': json.dumps(results),
}
requests.post(url="https://api.telegram.org/bot%s%s" % (telegram_bot_token, "/answerInlineQuery"),
params=my_data)
Note that I use params to supply the data.
I am getting the correct response after doing some POC. I am using java com.github.pengrad.
Below the code.
GetUpdatesResponse updatesResponse = bot.execute(new GetUpdates());
List updates = updatesResponse.updates();
for(Update update:updates){
InlineQuery inlineQuery = update.inlineQuery();
System.out.println(update);
System.out.println(inlineQuery);
System.out.println("----------------");
if(inlineQuery!=null) {
InlineQueryResult r1 = new InlineQueryResultPhoto("AgADBQADrqcxG5q8tQ0EKSz5JaZjzDWgvzIABL0Neit4ar9MsXYBAAEC", "https://api.telegram.org/file/bot230014106:AAGtWr8xUCqUy8HjSgSFrY3aCs4IZs00Omg/photo/file_1.jpg", "https://api.telegram.org/file/bot230014106:AAGtWr8xUCqUy8HjSgSFrY3aCs4IZs00Omg/photo/file_1.jpg");
BaseResponse baseResponse = bot.execute(new AnswerInlineQuery(inlineQuery.id(), r1)
.cacheTime(6000)
.isPersonal(true)
.nextOffset("offset")
.switchPmParameter("pmParam")
.switchPmText("pmText"));
System.out.println(baseResponse.isOk());
System.out.println(baseResponse.toString());
System.out.println(baseResponse.description());
}
}
Below the console output:
Update{update_id=465103212, message=null, edited_message=null, inline_query=InlineQuery{id='995145139265927135', from=User{id=231700283, first_name='Manabendra', last_name='Maji', username='null'}, location=null, query='hi', offset=''}, chosen_inline_result=null, callback_query=null}
InlineQuery{id='995145139265927135', from=User{id=231700283, first_name='Manabendra', last_name='Maji', username='null'}, location=null, query='hi', offset=''}
true
BaseResponse{ok=true, error_code=0, description='null'}
null
And I am getting proper response in my mobile telegram app also.
I'm building an app and I want to make some tests. I need to convert the response data from the test client to JSON.
The app:
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good Python tutorial on the web',
'done': False
}
]
app = Flask(__name__, static_url_path="")
#app.route('/myapp/api/v1.0/tasks', methods=['GET'])
def get_tasks():
return jsonify({'tasks': [task for task in tasks]})
if __name__ == '__main__':
app.run(debug=True)
The tests:
class MyTestCase(unittest.TestCase):
def setUp(self):
myapp.app.config['TESTING'] = True
self.app = myapp.app.test_client()
def test_empty_url(self):
response = self.app.get('/myapp/api/v1.0/tasks')
resp = json.loads(response.data)
print(resp)
if __name__ == '__main__':
unittest.main()
When I try to convert response.data to JSON, I get the following error:
TypeError: the JSON object must be str, not 'bytes'
How can I fix this error and get the JSON data?
Flask 1.0 adds the get_json method to the response object, similar to the request object. It handles parsing the response data as JSON, or raises an error if it can't.
data = response.get_json()
Prior to that, and prior to Python 3.6, json.loads expects text, but data is bytes. The response object provides the method get_data, with the as_text parameter to control this.
data = json.loads(response.get_data(as_text=True))