Connecting my Python backend with my Flutter Frontend using Flask - python

So currently I am trying to learn how to connect a flutter front end with a Python backend using flask and I am making a basic project where you basically input a number in the flutter app the number you input being the index of a list I have stored in my python app the python app will then return the number at the index you specified and it will be displayed on the screen. The issue I am having is that when I run the applications the flutter application just displays an error message. I have tried a whole bunch of things and can't figure out what is wrong
Here is the link to the screenshot of my Flutter App (Includes error message received from the server):
https://imgur.com/a/K6KYRAu
Here is my Python Code
from flask import Flask
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
myList = [3,4,8,1,9,4,2,0,2,9,3,8,4,7,2,7,0,1]
#app.route('/', methods = ['GET'])
class Update(Resource):
def get(self,pos):
if(pos > len(myList)):
return {"num" : "invalid number: out of list range"}
else:
return {"num": str(myList[pos])}
api.add_resource(Update, "/Update/<int:pos>")
if __name__ == "__main__":
app.run(debug=True)
here is my Flutter Code:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Entry> fetchEntry() async {
final response =
await http.get('https://127.0.0.1:5000/Update/3');
if (response.statusCode == 200) {
return Entry.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load Entry');
}
}
class Entry {
final String number;
Entry({this.number});
factory Entry.fromJson(Map<String, dynamic> json) {
return Entry(
number: json['num'],
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<Entry> futureEntry;
#override
void initState() {
super.initState();
futureEntry = fetchEntry();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Entry>(
future: futureEntry,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.number);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Also I have double checked my dependencies in my pubspec.yaml file and AndroidManifest.xml file so that shouldn't be the issue. Any help would be greatly appreciated, thanks.
EDIT: for clarification I am using and android emulator for this and have tried using a different ip address for my flutter get request (I found the ip address when trying to figure out how to fix this problem and it said that ip address needs to be used for android emulators) but it still returned the same error when I did that.

Not exactly sure why this is throwing this error as you do specify the port as 5000, but a simple solution would be to change the flask port to 50162.
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=50162)
EDIT:
On further review, you might want to change your http request in the flutter code to http, not https.

I figured out the solution:
for my get request I need to be using an IP address that can be used by android the IP address that android uses is 10.0.2.2 I found this solution on this stack overflow post:
How to connect to my http://localhost web server from Android Emulator

Related

Weird Axios Network Error with seemingly error-free code

I am trying to use react to get data from an API (Python, I'm hosting it on the same machine).
API Code:
from flask import Flask, jsonify, request
app = Flask(__name__)
#app.route('/')
def all_data():
all_data = "Hello"
return jsonify({
'data':all_data,
'message':"success"
}), 200
if __name__ == "__main__":
app.run(debug=True)
React code(Didn't include the render()):
export default class HomeScreen extends Component {
constructor(props){
super(props);
this.state = {
listData:[],
url:"http://localhost:5000"
}
}
getPlanets=()=>{
console.log("Axios called")
const url = this.state.url;
console.log(url)
axios.get(url).then((response)=>{
console.log(response.data)
return this.setState({listData:response.data})
}).catch((error)=>{
console.log(error.message)
Alert.alert(error.message);
})
}
componentDidMount(){
this.getPlanets();
}
}
I'm always getting Network Error for the console.log(error.message).
I'm also getting a larger Error: "Network Error" in Error: Network Error << at e.exports (axios.js:3:7286) << at d.onerror (axios.js:3:6270) for console.log(error).
Simultaneously, I got two weird error messages in my API:
code 400, message Bad request version ('localhost\x00\x17\x00\x00ÿ\x01\x00\x01\x00\x00')
"▬♥☺☻☺☺ü♥♥ÆuaTÁS¾eài ¸ ²`½‼/cùCf{&*½(¨qh↓(â®z↨Ó ×D ÚÚ‼☺‼☻‼♥À+À/À,À0̨̩À‼À¶úú♫♀ l
ocalhost↨ÿ☺☺" HTTPStatus.BAD_REQUEST -
Help?
I've tried looking through a lot of websites for the problem, but they all just suggested adding the http:// prefix to my url, which I had already done. I'm also using Python for the API and not NodeJS, so I don't need to use CORS. I just couldn't find a relevant fix anywhere.

Unable to send flutter GET request to python local server

I've made a simple flutter web app with TextField() and a Text() widget. When I press the button I expect it to send a query to the simple flask app made using python where it will returns the inverted text and I display that on the Text widget.
NOTE: Inverting text is not the actual task. Its just to check if I'm
able to get the data.
Python Code:
This code works when I run on the chrome.
#performing flask imports
from flask import Flask,jsonify
from flask.globals import request
app = Flask(__name__) #intance of our flask application
#Route '/' to facilitate get request from our flutter app
#app.route("/api",methods=["GET"])
def function():
d = {}
text = str(request.args["Query"])
text = text[::-1]
d["query"] = text
return jsonify(d)
if __name__ == "__main__":
app.run()
Flutter Code:
main.dart
import 'package:flutter/material.dart';
import 'api.dart';
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String url;
var data;
String queryText = "Query";
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("PYTHON AND FLUTTER"),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
onChanged: (value) {
url = "http://10.0.2.2:5000/api?Query=" + value.toString();
},
decoration: InputDecoration(
hintText: "Search Anything Here",
suffixIcon: GestureDetector(
onTap: () async {
data = await getData(url);
var decodedData = jsonDecode(data);
setState(() {
queryText = decodedData["Query"];
});
},
child: Icon(Icons.search))),
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
queryText,
style: TextStyle(fontSize: 30.0, fontWeight: FontWeight.bold),
),
),
],
),
),
);
}
}
api.dart
import 'package:http/http.dart' as http;
Future getData(url) async {
http.Response response = await http.get(url);
return response.body;
}
I followed the tutorial from : This Youtube Video
I'm running the python code via Command Prompt and flutter app through VScode.
I'm getting the following errors:
Error: Expected a value of type 'Uri', but got one of type 'String'
at Object.throw_ [as throw] (http://localhost:50523/dart_sdk.js:5348:11)
at Object.castError (http://localhost:50523/dart_sdk.js:5319:15)
at Object.cast [as as] (http://localhost:50523/dart_sdk.js:5635:17)
at Function.as_C [as as] (http://localhost:50523/dart_sdk.js:5263:19)
at getData (http://localhost:50523/packages/word_prediction/api.dart.lib.js:29:47)
at getData.next (<anonymous>)
at runBody (http://localhost:50523/dart_sdk.js:39211:34)
at Object._async [as async] (http://localhost:50523/dart_sdk.js:39242:7)
at Object.getData (http://localhost:50523/packages/word_prediction/api.dart.lib.js:28:18)
at main._MyAppState.new.<anonymous> (http://localhost:50523/packages/word_prediction/main.dart.lib.js:422:48)
at Generator.next (<anonymous>)
at runBody (http://localhost:50523/dart_sdk.js:39211:34)
at Object._async [as async] (http://localhost:50523/dart_sdk.js:39242:7)
at http://localhost:50523/packages/word_prediction/main.dart.lib.js:421:210
at tap.TapGestureRecognizer.new.invokeCallback (http://localhost:50523/packages/flutter/src/gestures/recognizer.dart.lib.js:203:18)
at tap.TapGestureRecognizer.new.handleTapUp (http://localhost:50523/packages/flutter/src/gestures/tap.dart.lib.js:417:40)
at tap.TapGestureRecognizer.new.[_checkUp] (http://localhost:50523/packages/flutter/src/gestures/tap.dart.lib.js:223:12)
at tap.TapGestureRecognizer.new.acceptGesture (http://localhost:50523/packages/flutter/src/gestures/tap.dart.lib.js:199:23)
at arena.GestureArenaManager.new.sweep (http://localhost:50523/packages/flutter/src/gestures/arena.dart.lib.js:222:31)
at binding$5.WidgetsFlutterBinding.new.handleEvent (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:402:27)
at binding$5.WidgetsFlutterBinding.new.dispatchEvent (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:381:24)
at binding$5.WidgetsFlutterBinding.new.dispatchEvent (http://localhost:50523/packages/flutter/src/rendering/layer.dart.lib.js:6107:13)
at binding$5.WidgetsFlutterBinding.new.[_handlePointerEventImmediately] (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:352:14)
at binding$5.WidgetsFlutterBinding.new.handlePointerEvent (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:325:43)
at binding$5.WidgetsFlutterBinding.new.[_flushPointerEventQueue] (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:314:14)
at binding$5.WidgetsFlutterBinding.new.[_handlePointerDataPacket] (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:304:65)
at Object.invoke1 (http://localhost:50523/dart_sdk.js:185426:7)
at _engine.EnginePlatformDispatcher.__.invokeOnPointerDataPacket (http://localhost:50523/dart_sdk.js:165747:15)
at _engine.PointerBinding.__.[_onPointerData] (http://localhost:50523/dart_sdk.js:166405:49)
at http://localhost:50523/dart_sdk.js:166863:28
at http://localhost:50523/dart_sdk.js:166816:16
at http://localhost:50523/dart_sdk.js:166509:11
I don't know what I'm doing wrong here.
Try this:
Future getData(String url) async {
var response = await http.get(Uri.parse(url));
return response.body;
}
Along this change https://stackoverflow.com/a/66517561/13592012 mentioned by Ουιλιαμ Αρκευα.
There was another problem:
When I use Break point it shows file call by blinding.dart
This was because of CORS.
Cross Origin Request(CORS) error which was because I did not set this up in my server.
This is especially if your flutter web application is not running in the same domain as the server where you api is running. Even if its on the same machine, you will have to allow the request from certain domain and ports.
This can be done by adding the following lines to flask code:
response.headers.add("Access-Control-Allow-Origin", "*")
and
response.headers.add("Access-Control-Allow-Credentials", "true")
So the updated code will be:
#performing flask imports
from flask import Flask,jsonify
from flask.globals import request
app = Flask(__name__) #intance of our flask application
#Route '/' to facilitate get request from our flutter app
#app.route("/api",methods=["GET"])
def word_predictor():
d = {}
text = str(request.args["Query"])
text = text[::-1]
d["Query"] = text
response = jsonify(d)
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Credentials", "true")
return response
if __name__ == "__main__":
app.run()
And, with these two changes, code works fine.

Exception when receiving data from Back end to Front end [duplicate]

This question already has answers here:
Configure Flask dev server to be visible across the network
(17 answers)
Closed 1 year ago.
I've created a simple flutter app which will get data from an api in json format sent from the backend (Python flask) and print out the data on click of a button.
When I click on the button, I get the error
[ERROR:flutter/lib/ui/ui_dart_state.cc(177)]
Unhandled Exception: SocketException: OS Error: Connection refused, errno = 111, address = 127.0.0.1, port = 36820
I'm very new to flutter, please tell me where I did wrong and help me figure it out.
Flutter Dart code:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(new MaterialApp(
home: new HomePage(),
));
}
class HomePage extends StatefulWidget {
#override
HomePageState createState() => new HomePageState();
}
class HomePageState extends State<HomePage> {
List data;
Future<String> getData() async {
var response = await http.get(
Uri.encodeFull("http://127.0.0.1:5000/ "),
headers: {
"Accept": "application/json"
}
);
data = json.decode(response.body);
print(data);
return "Success!";
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new RaisedButton(
child: new Text("Get data"),
onPressed: getData,
),
),
);
}
}
Python code:
from flask import Flask, jsonify
app = Flask(__name__)
#app.route('/')
def hello_world():
return jsonify({"about": "Hello World!"})
if __name__ == '__main__':
app.run()
Looks like you are running your back-end from localhost. In this case, 127.0.0.1 will only work if you run the application on your PC (and not another phone/device. Not sure about simulators though).
Trying to access 127.0.0.1 from a phone is like trying to access a server hosted on your phone (which evidently will not be found).
So, to run the app on your phone, you need to find your PC's (private) IP address, using e.g. ifconfig from your terminal. Once you get this IP address, use the URL {your-priv-IP}:5000 instead of 127.0.0.1:5000 in your code. Make sure though that your PC and phone are connected to the same Wifi network for this to work.

Using fetch to get a simple string from flask api

I am trying to connect my flask api to my react app and all I want from that is to display the string I returned from the flask on react app.
In doing so, I used useEffect(), but my variable in react is not changed but just keeps the original state. When I use console.log to see the value that I am passing to the variable, it shows an error saying "Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0".
App.js looks like:
import React, {Component, useState, useEffect} from 'react';
import './App.css';
function App() {
const [block, setBlock] = useState(0);
useEffect(() => {
fetch('/video').then(res => res.json()).then(data => {
setBlock(data.text);
console.log(data.text);
});
}, []);
return (
<div className="App">
<header className="App-header">
<p>Text: {block}</p>
</header>
</div>
);
}
export default App;
part of flask(flask.py):
#app.route('/video')
def video():
return {'text': text}
Any insight would be greatly appreciated!
If you want to return JSON from a Flask route use flask.jsonify.
from flask import jsonify
#app.route('/video')
def video():
return jsonify({'text': text})

Sending Image from Android with Retrofit and Getting the Image with Python Flask

I am trying to send an image to flask endpoint from android application using retrofit 2 but I seem to fail every time. Flask endpoint is working with both html and postman posts so the problem is on the retrofit part.
Here is the Flask endpoint:
#app.route("/uploadfile", methods=["POST"])
def uploadsingle():
file = request.files['file']
file.save(os.path.join("/home/moralalp/mysite/", file.filename))
return "Success"
Below is the interface for retrofit:
#Multipart
#POST("uploadfile")
Call<ResponseBody> uploadPhoto(#Part("description") RequestBody description, #Part MultipartBody.Part file);
And finally, the uploadFile method:
private void uploadFile(Uri fileUri) {
final EditText name = findViewById(R.id.editText);
RequestBody descriptionPart = RequestBody.create(MultipartBody.FORM, name.getText().toString());
File originalFile = new File(getRealPathFromURI(fileUri));
RequestBody filePart = RequestBody.create(MediaType.parse(getContentResolver().getType(fileUri)), originalFile);
MultipartBody.Part file = MultipartBody.Part.createFormData("file", originalFile.getName(), filePart);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("https://mysite.pythonanywhere.com/")
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
UserClient client = retrofit.create(UserClient.class);
Call<ResponseBody> call = client.uploadPhoto(descriptionPart, file);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Toast.makeText(MainActivity.this, "YEAH", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(MainActivity.this, "NOOO", Toast.LENGTH_SHORT).show();
}
});
}
I keep getting "NOOO" Toast message so I can not even get a response, what could be the problem here?
As for this error please use the next line to figure out what is the problem and please edit your question to contain it
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(MainActivity.this, "NOOO", Toast.LENGTH_SHORT).show();
Log.d("Error_TAG", "onFailure: Error: " + t.getMessage());
}
After that Please Filter your log cat to the Error_TAG and Add the Error in the Question
Good Luck
Ok so adding the following in the AndroidManifest.xml file solved my problem:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting Android Q. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>

Categories