How to contact flask-restful api from react native app? - python

i am new to backend dev. I try to developp a flask restful api. I followed the documentation and made the suggested minimal api, that is just returning a jsonified dict. With postman, curl and in the browser, no problem, the api is running and responds to my requests.
From my react native app however, i always get a Netwrok Error.
I tried lots of things:
- multiple IP addresses for the flask serveur
- differents ways to use axios
- different os : win10, ubuntu
- different endpoints : /, /api, /test
- different ways of writing the api (flask-restful class, flask app functions ...)
- manips from web documentations : dev mode of my device, chrome dev tools (port forwarding)
- i asked a react native developper to check my client-side code, nothing wrong according to him,
precisions :
- python code runs under a conda virtual env
- appli runs under node js and expo
- container folders of my app and my api are at the same level
- the flask server does not respond 404 or whatever, it does not respond at all, the error returned in react native is a network error
- depending on url, the network errors occurs immediately or after a 2 minutes delay
- flask shows requests and status when called by postman, curl, chrome, but does not react when i press my buttons from the react native app
Here is (one of) my python code:
from flask import (Flask, jsonify)
# from flask_restful import Resource, Api
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app)
#app.route("/api", methods=["GET"])
def get():
return jsonify(hello='bouh !')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000, debug=True)
and here is the clientside code:
import React, {Component} from 'react';
import { View, Button } from 'react-native';
import axios from 'axios';
import { sharedStyles } from '../../SHARED/_shared';
var url = "http://192.168.1.16:5000/api";
export default class PrevCommune extends Component {
constructor(props){
super(props);
this.navigation=this.props.navigation;
};
getAxios=()=>{
axios.get(`${url}`).then((response)=>{
console.log("succes axios :",response);
}).catch((error)=>{
console.log("fail axios :", error);
});
};
getFetch=()=>{
fetch(url).then((response)=>{
console.log("succes fetch :",response)
}).catch((error)=>{
console.log("fail fetch :",error)
})
}
render(){
return (
<View style={sharedStyles.mainContainer}>
<Button onPress={()=>this.getAxios()} title={"get axios"}></Button>
<Button onPress={()=>this.getFetch()} title={"get fetch"}></Button>
</View>
);
};
};
And the lines returned by requests:
fail axios : [Error: Network Error]
fail fetch : [TypeError: Network request failed]
I saw lots of tutos, videos, articles on flask api but i didn't find where i am wrong. Please tell me if you have any ideas ! I think both client and server codes are ok, the problem seems to be that my requests are blocked by something.

Solved : the probleme was my firewall ... thank you ricardo for the CORS doc =)

What worked for me was to change the IP address of localhost to my network IP in the api call in react native and then starting the flask application using the below command.
flask run --host=0.0.0.0

Related

React app can't reach to backend python application on localhost on same server

I have a public cloud VM which has public IP say 160.159.158.157 (this has a domain registered against it).
I have a Django application (backend) which is CORS-enabled and serves data through port 8080.
I have a React app running on the same VIM on a different port (3000), which is accessing the Django app and is supposed to produce a report.
The problem is that, when I use http://<domain-name>:8080/api/ or http://<public-ip>:8080/api/, my application is working fine,
but when I try to fetch data from localhost like http://localhost:8080/api/ or http://127.0.0.1:8080/api/, the React app fails to fetch data with the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:8080/api/. (Reason: CORS request did not succeed). Status code: (null).
Here's what I've tried:
axios.get(baseURL, { headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,PATCH,OPTIONS',
}
but it didn't work. What should I do?
Looks like you've gotten confused where those headers need to be. You're setting them on the request to the backend, but they need to be set on the response from the backend. After all, it wouldn't be very good security if someone making a request could simply say "yeah, I'm ok, you should trust me".
The problem is going to be somewhere in your backend Django app, so double check the CORS config over there.

Woocomerce webhook not being recieved

I am playing around with the webhooks of WooCommerce and i have setup a hook that triggers when an item is being added to a cart.
I have a little Flask app that listens to requests and prints them out.
from flask import Flask, request, Response
app = Flask(__name__)
#app.route('/webhook', methods=['POST'])
def respond():
print(request.json);
return Response(status=200)
This script is being run on the same machine as the Wordpress server.
But when i add an item to my cart no calls are being made.
Does anyone know what i am doing wrong?
I still am unable to trigger any webhook to an url that points to an service on the same machine. I tried running my endpoint in a docker container and addressing the ip address of the container. I also tried making custom dns entries in my host file. Still didnt work. Eventually fixed my problem by using ngrok.

VUE axios get API not found

I have an app Vue + Django. I try to send some data from vue to database using axios post method. Unfortunately console shows error:
GET http://localhost:8080/api/get_data/ 404 (Not Found)
And the same happend in python console:
Not Found: /get_data/
I have function get_data defined in my views and i added a path to urls:
path('get_data/', views.get_data)
In frontend it looks like this:
addNewData() {
axios.post("/api/get_data/", this.componentData.data).then(response => {
console.log("ok");
});
}
Did I missed something?
axios.post("/api/get_data/" - this URL is relative to "current". That's why it is trying ot access http://localhost:8080/... where 8080 is the port of VUE app. Whereas Django app is running by default on 8000.
You should use absolute URLs to access one app from another: to access Django app API from Vue app.
Use different config/env.var in your VUE app to refer to backend API in debug (localhost) and prod (domain name + http/https) modes, like:
axios.post(conf.BACKEND_URL + "/api/get_data/")
in your case, in debug mode it should be (expanded):
axios.post("http://localhost:8000/api/get_data/")
if you don't used webpack proxyTable deal with '/api' ,you should add the backend address

write a reverse proxy in node js to call the api in django

My frontend code is running in angular at node httpserver port 127.0.0.1:8081
My backend services runnning in python django framework at port 127.0.0.1:9000
While calling my backend servies from angular http methods throws cors exception
so i wrote a proxy controller in my node js
var http = require('http'),
httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer();
http.createServer(function (req, res) {
// This simulates an operation that takes 500ms to execute
setTimeout(function () {
proxy.web(req, res, {
target: 'http://127.0.0.1:9000/dummy/'
});
}, 500);
}).listen(8080, "127.0.0.1");
to listen and bind at angular. i run as the node proxycontroller.js, results a another port no 127.0.0.1:8080
from proxy controller it calls my backend service and result json but from the angular js calling the proxy controller from the http.get() method results cors problem
please help to solve this problem.
Enable CORS in Django
Uses this third-party lib django-cors to do it.
You are getting CORS because you are making the call from your AngularJS app and its host is 127.0.0.1:8081, different from your Django app host 127.0.0.1:9000
The error said CORS is supported only for specific protocals like http:// etc. So you have to add http to that url. When you say, 127.0.0.1, the browser is unable to understand which protocol to use to access that url, should it be using http:// or data:// or chrome:// etc. So you've to explicitly say http://
You have to configure cors in the backend. The backend (the API server) much explcitly say a site is allowed using the http header I specified earlier. Otherwise, I can open your website, edit the frontend using chrome console and remove all the security stuff. It has the be in the backend.
as http://127.0.0.1:9000 from the front end angular app, dosent need to create proxy server to transfer the calls to backend service.

How safe is my Flask REST API?

My website is on http protocol. My flask API is secured via flask-httpauth (https://github.com/miguelgrinberg/Flask-HTTPAuth).
There is a Tornado web server in front of my Flask API which listens on a private port 5000. Client API requests first go to Tornado server which then calls the Flask API
This is the flow I've got going:
My website (on http) ---> corpauthentication (on https) --> back to my website (http) --> client calls Tornado server --> Tornado calls Flask API and returns results
How safe is my API and website? I was reading this link Security of python flask REST API using HTTP Basic Authentication and it seems to me that the API is secure but I can never be sure.
If its not safe, what else do you think I can do to make it more secure? Since corpauthentication is required to get in, I feel on the UI side it is pretty safe. But lets say someone is listening on my port 80, will they be able to track any API requests made even when there is tornado + httpbasic auth in place?
This is my Tornado Server code:
from tornado.wsgi import WSGIContainer
from tornado.ioloop import IOLoop
from tornado.web import FallbackHandler, RequestHandler, Application
from flaskfile import app
class MainHandler(RequestHandler):
def get(self):
self.write("This message comes from Tornado ^_^")
tr = WSGIContainer(app)
application = Application([
(r"/tornado", MainHandler),
(r".*", FallbackHandler, dict(fallback=tr)),
])
if __name__ == "__main__":
application.listen(5000)
IOLoop.instance().start()
This is how I'm calling the API from my Javascript:
$.ajax({
url: 'http://x.x.x:5000/data',
type: 'GET',
dataType: 'json',
async: false,
headers: {
"Authorization": "Basic " + btoa("username" + ":" + "password")
},
data: {start: startdate, end: enddate},
success: function(result) {
data = result.results;
}
});
No, this is not secure - the comments in the other question you linked to are entirely correct. (BTW your question is really a duplicate of that).
Authentication over regular unencrypted HTTP is never secure - the username and password will be visible to any device between the user and the webserver, in plain text. As a first step you should implement SSL/TLS to encrypt the authentication information.
Tornado really needs to sit behind a web proxy of some sort. You could use either Apache or Nginx to fulfil this role. There are instructions for setting up Tornado+Nginx in this related question.

Categories

Resources