Making an Angular2 POST with JSON - python

I have a simple Flask backend for the API, and want to make a POST.
I'm not sure the error is-I get the error message, but am unsure if its an Angular or Flask issue. I tried request.get_json() in my Flask, and got
{BadRequest}400 BadRequest: The browser (or proxy) sent a request that
this server could not understand
Angular2 call in my service.ts:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import { Observable} from 'rxjs/Rx';
import { Headers } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
export class NicksService {
private headers = new Headers({'Content-Type': 'application/json'});
nickUrl: string = "http://localhost:5000/nick";
constructor(private http: Http) { }
// Send the nick to the server to see if it is valid
checkNickValidity(nickName: string): Observable<string>{
return this.http.post(this.nickUrl, JSON.stringify({nick: nickName}), {headers: this.headers})
.map(this.extractData)
.catch(this.handleError)
}
Flask backend:
from flask_cors import CORS
from flask.ext.api import FlaskAPI
from flask import request
app = FlaskAPI(__name__)
CORS(app)
#app.route('/')
#app.route('/nick', methods=['POST'])
def check_nick():
try:
nick = request.json
if nick =='AmandaPanda':
return 'Good'
else:
return 'No nick found'
except:
return 'error'
if __name__ == '__main__':
app.run()

I think you have problems on both sides of your application.
Client side:
Angular's Http's post method receives any object in for the body parameter, meaning you don't need to stringify it.
E.g.:
this.http.post(this.nickUrl, {nick: nickName}, {headers: this.headers})
Server side:
Once the client's request arrived properly to the server, you are not getting the data properly.
What you need to do is something like this:
from flask import jsonify
(... your code ...)
data = request.json
nick = data.get('nick')
if nick == 'AmandaPanda':
return jsonify({'message': 'good'}), 200
else:
return jsonify({'message': 'no nick found'}), 400
Here, the json data is stored as a dictionary in the variable data. Later, the nick is obtained from the nick key of said dictionary.
Finally, it is a better practice to return to the client in json form. That's what Flask's jsonify method is for. Notice the 200 and 400 status codes appended to the response, to indicate to the client if the request was properly accepted (200) or if it was a bad request (400).

Related

Get data from an API with Flask

I have a simple flask app, which is intended to make a request to an api and return data. Unfortunately, I can't share the details, so you can reproduce the error. The app looks like that:
from flask import Flask
import requests
import json
from requests.auth import HTTPBasicAuth
app = Flask(__name__)
#app.route("/")
def getData():
# define variables
username = "<username>"
password = "<password>"
headers = {"Authorization": "Basic"}
reqHeaders = {"Content-Type": "application/json"}
payload = json.dumps(
{
"jobType": "<jobType>",
"jobName": "<jobName>",
"startPeriod": "<startPeriod>",
"endPeriod": "<endPeriod>",
"importMode": "<importMode>",
"exportMode": "<exportMode>"
}
)
jobId = 7044
req = requests.get("<url>", auth=HTTPBasicAuth(username, password), headers=reqHeaders, data=payload)
return req.content
if __name__ == "__main__":
app.run()
However, when executed this returns error 500: Internal Server Error
The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
The same script but outside a flask app (just the function as it is defined here) runs with no problems at all.
What am I doing wrong?
flask app return format json. If you return req.content, it will break function. You must parse response request to json before return it.
from flask import jsonify
return jsonify(req.json())
It's better with safe load response when the request fail
req = requests.get()
if req.status_code !=200:
return {}
else:
return jsonify(req.json())

How can i build a proper restful response API by python flask for parameters

I'm studing about RESFful API with python.
I want to build a my restful api server,
but i have a problem,
i don't know how my api server returns proper data by reqeust each parameters
(request code sample)
the request code wants to get the information about 'item' : 'sword'
import requests
import json
url = "https://theURL"
querystring={"item":"sword"}
response = requests.request("GET", url, params=querystring)
print (response.json())
(API server response code sample, by flask python)
from flask import Flask, url_for
from flask_restful import Resource, Api, abort, reqparse
app = Flask(__name__)
api = Api(app)
TODOS = {
"version":"2.0",
"resultCode":"OK",
"output":{
{
"item" :"sword"
"price": 300,
"damage": 20,
},
{
"item" :"gun"
"price": 500,
"damage": 30,
},
},
}
class Todo(Resource):
def post(self):
return TODOS
api.add_resource(Todo, '/item.price')
if __name__ == "__main__":
app.run(debug=True, host ="192.168.0.8", port = 8080)
So i want to know how i use a code in response api server for returning 'item price' data by reqeusted parameters 'item : sword'
I just want to get the selected parameter's item price and damage information.
I thought it might be very easy, i'm tried to search the example but i couldn't find proper sample code.
I'm not a Flask-expert, but this helps setting up and running a minimalistic Flask-server. Then, this explains how to return json-formatted data from your server, and finally how to request and interpret the json-response can be found here. Summarized below:
Server returning a json-formatted data:
from flask import Flask
from flask import jsonify
app = Flask(__name__)
#app.route('/')
#app.route('/index')
def hello():
return "Hello, World!"
#app.route('/request_sword')
def grant_sword():
return jsonify({"sword": {"name":"Excalibur","price":"stack overflow"}})
Client requesting json-formatted data:
import json
import urllib.request
url = "http://127.0.0.1:5000/request_sword" ## My local host flask server
data = urllib.request.urlopen(url)
response = json.loads(data.read())
print(response)
That's all really. You may also just enter the url in your browser, which will correctly read the json-data:

Flask session not persisting between requests for Angular App

I have an Angular app that needs to call a Flask server that use sessions to store information between requests.
I also have an older JS app that called the same server using XMLHttpRequest, that I am replacing with the new Angular app.
The trouble is that when the old app was making a request, session cookies were working as expected but now with the angular app it does not.
All interactions are done over localhost. The Flask server is accessible from localhost:5000, and the Angular app from localhost:4200.
The old app was doing request like this:
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "http://localhost:5000/api/getAll", true);
xhttp.withCredentials = true;
xhttp.send();
The Angular app is doing like so:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, } from '#angular/common/http';
import { Observable } from 'rxjs';
const httpOptions = {
withCredentials: true,
headers: new HttpHeaders({
'Content-Type': 'application/json',
'charset': 'UTF-8',
})
};
#Injectable()
export class ServerService {
url = "http://localhost:5000/api/"
constructor(private http:HttpClient) { }
getAll(): Observable<string>{
return this.http.get<string>(this.url + 'getAll', httpOptions);
}
login (username: string): Observable<string> {
return this.http.post<string>(this.url + 'login', JSON.stringify({"username": username}), httpOptions)
}
}
And the Flask server:
from flask import Flask, session, request, jsonify
from flask_cors import CORS
import os
import Person
import multiprocessing as mp
import json
import Insurance
import datetime
import Functions
import missingVal
app = Flask(__name__)
CORS(app, supports_credentials=True)
# set the secret key. keep this really secret:
# The value come from calling os.urandom(24)
# See https://stackoverflow.com/a/18709356/3729797 for more information
# app.secret_key = b'fL\xabV\x85\x11\x90\x81\x84\xe0\xa7\xf1\xc7\xd5\xf6\xec\x8f\xd1\xc0\xa4\xee)z\xf0'
app.config['SECRET_KEY'] = b'fL\xabV\x85\x11\x90\x81\x84\xe0\xa7\xf1\xc7\xd5\xf6\xec\x8f\xd1\xc0\xa4\xee)z\xf0'
#app.route('/api/getAll')
def getAll():
response = jsonify()
if 'username' in session:
user = users[session['username']]
# some more logic here
response = jsonify({'username': session['username']})
return response
# login and account creation
#app.route('/api/login', methods=['POST'])
def login():
response = jsonify()
if users.get(request.json.get('username')) is not None:
session['username'] = request.json.get('username')
# some more logic here
response = jsonify({'username': session['username']})
response.headers.add('Access-Control-Allow-Methods',
'GET, POST, OPTIONS, PUT, PATCH, DELETE')
response.headers.add('Access-Control-Allow-Headers',
"Origin, X-Requested-With, Content-Type, Accept, x-auth")
return response
if __name__ == '__main__':
# some more logic here
app.run(host='localhost', threaded=True
The problem is that when I log in, it push information into the session, and when I do another request, I check if that information is in the session but it does not.
I found a lot of other related question on StackOverflow:
this one has to do with setting the secret_key multiple times, which is not my problem.
this one talk about static versus dynamic configuration in init but I don't think it has anything to do with my problem? Tell me if I'm wrong.
this one and this other one had trouble because their payload inside the cookie was too big, only 4096bytes or less are allowed it seems. But I only put a username that is a few letters into my cookie so I don't believe it is my problem.
this one I thought was related to my problem because it deals with localhost, but it turns out that it was because OP was mixing requests on 127.0.0.1 and localhost and cookies are processed separately by flask apparently. I do all my request on localhost so not related I believe.
I'm a bit lost right now, there is probably something very obvious I am missing but can't figure it out, any suggestion appreciated
I got it working by adding
response.headers.add('Access-Control-Allow-Headers',
"Origin, X-Requested-With, Content-Type, Accept, x-auth")
in the Flask server before sending back all requests.
For example
#app.route('/api/doSomething', methods=['POST'])
def doSomething():
response = jsonify()
if 'username' in session:
# some logic here
response = jsonify(someData)
# here is the line I added
response.headers.add('Access-Control-Allow-Headers',
"Origin, X-Requested-With, Content-Type, Accept, x-auth")
return response
Apparently it is needed when doing CORS, some good informations on MDN

allowing CORS request with Flask and React

I am trying to connect a client with a server via ajax requests.
My client, running on localhost:8080, has a button which invokes a function that does a simple ajax request to a locally running server, localhost:5000.
onClick function:
handleClick() {
console.log("check flights button was clicked!");
console.log(this.state);
const baseUrl = 'localhost:5000'
ajax.get(`${baseUrl}/flights/${this.state.origin}_${this.state.destination}`)
.end((error, response) => {
if (!error && response) {
console.log('got a valid response from the server')
} else {
console.log(`Error fetching data from the server: `, error)
}
});}
the (very) simple server, implemented with Flask, is as follows:
from flask import Flask, request
from flask_restful import Resource, Api
from json import dumps
app = Flask(__name__)
api = Api(app)
class Flights(Resource):
def get(self, origin, destination):
answer = 'we got some data ' + origin + ' ' + destination
print answer
api.add_resource(Flights, '/flights/<string:origin>_<string:destination>')
if __name__ == '__main__':
app.run()
I can access the server if i simply go to localhost:5000/flights/origin_destination, which prints a message saying it received the origin and destination.
However, when I try to do the ajax request, I get the following error:
XMLHttpRequest cannot load localhost:5000/flights/Porto_Lisboa. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Any suggestions on how to correct this behaviour?
Thank you in advance.
As the error suggest, you're missing the protocol name in your request. Try to add it at the start of the string :
const baseUrl = 'http://localhost:5000'
instead of just localhost:5000

FB Messenger can't receive messages

I am trying to setup a messenger chatbot using the newly released messenger platform api. I setup a Python Flask server hosted on Heroku and have been adapting these instruction to try to get my page receiving the messages my server sends it: https://developers.facebook.com/docs/messenger-platform/quickstart
Thus far I have validated a callback url and have been able to receive messages when I post to my page on FB (i.e. when I message my page which is linked to my app on FB, my heroku logs show that the POST request is being received). However, when I try to send messages from my server to my app, I get the following JSON error response:
400: {"error":{"message":"(#100) param recipient must be non-empty.","type":"OAuthException","code":100,"fbtrace_id":"B3cni+LAmYU"}}
I am using the requests library to send requests to the page. Below is the code I am using to service POST requests:
import json
import os
import requests
from flask import Flask, request
app = Flask(__name__)
FB_MESSAGES_ENDPOINT = "https://graph.facebook.com/v2.6/me/messages"
FB_TOKEN = "EAADKWAcVj...AZDZD"
#app.route('/', methods=["POST"])
def chatbot_response():
req_data = request.data
data = json.loads(req_data)
print "Data: ", data
sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
print "Sender id: ", sender_id
send_back_to_fb = {
"entry": [{"messaging": [{"recipient": {"id": str(sender_id)}}]}],
"recipient": {
"id": str(sender_id)},
"message": "this is a test response message",
"recipient": str(sender_id), "access_token": FB_TOKEN
}
params_input = {"access_token": FB_TOKEN, "recipient": sender_id}
fb_response = requests.post(FB_MESSAGES_ENDPOINT,
params={"access_token": FB_TOKEN, "recipient": {"id": str(sender_id)}, "json": "recipient": {"id": str(sender_id)}},
data=json.dumps(send_back_to_fb))
print "Json of response: ", fb_response.json()
# handle the response to the subrequest you made
if not fb_response.ok:
# log some useful info for yourself, for debugging
print 'jeepers. %s: %s' % (fb_response.status_code, fb_response.text)
return "OK", 200
if __name__ == '__main__':
app.run(host="0.0.0.0")
I've tried countless different types of key/value encodings of the 'recipients' element into json but none of them seem to be understood by the FB graph service. How can I encode my request so that FB knows what the 'recipient' param is?
Thanks!
Edit:
It turns out I had to manually set the encoding type in the header of the POST request. Adding the following line made it so I could send interpretable text responses to FB:
headers = {'content-type': 'application/json'}
You can try these, both should work
headers = {'Content-type': 'application/json'}
response = requests.post(url, data=json.dumps(send_back_to_fb), headers=headers)
OR
response = requests.post(url, json=send_back_to_fb)
how about python library for using facebook messenger platform?
https://github.com/conbus/fbmq
from flask import Flask, request
from fbmq import Page
page = fbmq.Page(PAGE_ACCESS_TOKEN)
#app.route('/webhook', methods=['POST'])
def webhook():
page.handle_webhook(request.get_data(as_text=True))
return "ok"
#page.handle_message
def message_handler(event):
page.send(event.sender_id, "HI!!!")

Categories