[PYTHON] * Android * [HTTP communication_2] HTTP communication with Flask (hit WebAPI [GET, POST])

Introduction

In Previous article, I explained how to use HttpURLConnection using httpbin as a Web API. This time, we will use Flask as a Web API and perform HTTP communication (GET / POST) between Android and Flask. For a detailed explanation of the HttpURLConnection and curl commands, refer to Previous article.

Premise

*Android Studio 4.0.1 *targetSdkVersion 28 *Google Nexus 5x

curl command, python *Ubuntu 20.04 LTS (WSL 2) *Python 3.7.3

GET method

HTTP communication using the GET method can be easily realized. For Android side, please refer to Previous article. The code on the Android side is also written in the sample code shown at the end. Here, we will describe the Flask side.

app.py


from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/get', methods=['GET'])
def get():
    #Create a response to a GET request
    response = {'result': 'success', 'status': 200}
    #Return as JSON object
    return jsonify(response)

Let's send a request using the curl command.

curl http://127.0.0.1:5000/api/get

You should see a response like the one below.

{
  "result": "success",
  "status": 200
}

POST method

This section describes HTTP communication using the POST method.

Read JSON format data with flask

There are three ways to read JSON format data. This time, we will read the data received by the POST request.

app.py


from flask import Flask, request, jsonify
import json

app = Flask(__name__)

@app.route('/api/post', methods=['POST'])
def post():
    #Method 1
    #Request the data received by POST.If you retrieve the data, you can see that it is a bytes type.
    print(type(request.data))
    #Even if you output it, you can see that it is a bytes type
    print(request.data)
    #Since it is a bytes type, decode it to convert it to a character string
    print(request.data.decode('utf-8'))
    #A string written in JSON format can be converted to a dictionary type by the loads method.
    data = json.loads(request.data.decode('utf-8'))
    print(data)
    
    #Method 2
    #In the loads method, bytes type and bytearray type can be entered in addition to the character string.
    data = json.loads(request.data)
    print(data)
    
    #Method 3
    # request.By using the json method, the data received by POST can be treated as a dictionary type.
    #This is the fastest way to write, so I recommend it.
    print(request.json)
    
    #Adopt method 3 and return JSON object as return value
    data = request.json
    return jsonify(data)
    
    
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

Execute app.py and try sending a POST request using curl. Open a new terminal and execute the following command. The body describes a character string in JSON format.

curl -X POST -H 'Content-Type:application/json' -d `{"name": "foge", "value": "fogefoge"}` http://127.0.0.1:5000/api/post

When the curl command is executed, the following is output to the terminal where app.py is executed. It can be confirmed that the output of the bottom three lines is the same.

<class 'bytes'>
b'{"name": "foge", "value": "fogefoge"}'
{"name": "foge", "value": "fogefoge"}
{'name': 'foge', 'value': 'fogefoge'}
{'name': 'foge', 'value': 'fogefoge'}
{'name': 'foge', 'value': 'fogefoge'}

Json format on Android

In order to read the data of the character string written in JSON format sent from Android in Python, it is necessary to describe the body according to the JSON format on Android. Specifically, do as follows.

String postData = "{\"name\": \"foge\", \"value\": \"fogefoge\"}";

In this way, since it is necessary to describe double quotation marks in the character string, it is described using an escape sequence. If you want to embed variable data in a character string, write as follows.

String name = "foge";
int value = 100;

String postData = String.format("{\"name\": \"%s\", \"value\": %d}", name, value);

However, since it is very troublesome to describe in this way, it is generally described as follows.

//Create an associative array
HashMap<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "foge");
jsonMap.put("value", 100);
//Convert associative array to JSONObject
JSONObject responseJsonObject = new JSONObject(jsonMap);
//Convert JSONObject to a string
String postData = responseJsonObject.toString();

Sample code

Then, the sample code is shown below.

app.py


from flask import Flask, request, jsonify

app = Flask(__name__)
#If the result of jsonify contains Japanese, you can avoid garbled characters by writing the following one line.
app.config['JSON_AS_ASCII'] = False


@app.route('/api/get', methods=['GET'])
def get():
    response = {"result": "success", "status": 200}
    return jsonify(response)
    

@app.route('/api/post', methods=['POST'])
def post():
    data = request.json
    name = data['name']
    value = data['value']
    array = data['array']
    print(f'data: {data}')
    print(f'data["name"]: {name}')
    print(f'data["value"]: {value}')
    print(f'data["array"]: {array}')
    print(f'data["array[0]"]: {array[0]}')
    print(f'data["array[1]"]: {array[1]}')
    print(f'data["array[2]"]: {array[2]}')
    return jsonify(data)
    
    
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

Before writing the Android sample code, please check if HTTP communication is possible once with curl.

curl http://127.0.0.1:5000/api/get
curl -X POST -H 'Content-Type:application/json' -d '{"name": "foge", "value": 100, "array":["Good morning", "Hello", "Good evening"]}' http://127.0.0.1:5000/api/post

The Android sample code is shown below.

AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.samplehttpconnection">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:gravity="center"
        android:text=""
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="GET"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:gravity="center"
        android:text=""
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="POST"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.java


package com.example.samplehttpconnection;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();
    private Button button;
    private Button button2;
    private TextView textView;
    private TextView textView2;
    //Please change your IP address. Describe the IP address of the PC running the Python program
    private String urlGetText = "http://192.168.0.10:5000/api/get";
    private String urlPostText = "http://192.168.0.10:5000/api/post";
    private String getResultText = "";
    private String postResultText = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        button2 = findViewById(R.id.button2);
        textView = findViewById(R.id.textView);
        textView2 = findViewById(R.id.textView2);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String response = "";
                        try {
                            response = getAPI();
                            JSONObject rootJSON = new JSONObject(response);
                            getResultText = rootJSON.toString();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                textView.setText(getResultText);
                            }
                        });
                    }
                });
                thread.start();
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Thread thread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        String response = "";
                        try {
                            response = postAPI();
                            JSONObject rootJSON = new JSONObject(response);
                            postResultText = rootJSON.toString();
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                textView2.setText(postResultText);
                            }
                        });
                    }
                });
                thread.start();
            }
        });
    }

    public String getAPI(){
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        String result = "";
        String str = "";
        try {
            URL url = new URL(urlGetText);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(10000);
            urlConnection.setReadTimeout(10000);
            urlConnection.addRequestProperty("User-Agent", "Android");
            urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(false);
            urlConnection.connect();
            int statusCode = urlConnection.getResponseCode();
            if (statusCode == 200){
                inputStream = urlConnection.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
                result = bufferedReader.readLine();
                while (result != null){
                    str += result;
                    result = bufferedReader.readLine();
                }
                bufferedReader.close();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }

    public String postAPI(){
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        String result = "";
        String str = "";
        try {
            URL url = new URL(urlPostText);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(10000);
            urlConnection.setReadTimeout(10000);
            urlConnection.addRequestProperty("User-Agent", "Android");
            urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
            urlConnection.addRequestProperty("Content-Type", "application/json; charset=UTF-8");
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.connect();
            outputStream = urlConnection.getOutputStream();

            HashMap<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("name", "foge");
            jsonMap.put("value", 100);
            ArrayList<String> array = new ArrayList<>();
            array.add("Good morning");
            array.add("Hello");
            array.add("Good evening");
            jsonMap.put("array", array);
            JSONObject responseJsonObject = new JSONObject(jsonMap);
            String jsonText = responseJsonObject.toString();
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"));
            bufferedWriter.write(jsonText);
            bufferedWriter.flush();
            bufferedWriter.close();

            int statusCode = urlConnection.getResponseCode();
            if (statusCode == 200){
                inputStream = urlConnection.getInputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                result = bufferedReader.readLine();
                while (result != null){
                    str += result;
                    result = bufferedReader.readLine();
                }
                bufferedReader.close();
            }

            urlConnection.disconnect();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str;
    }
}

Page you want to see

-Previous article

Recommended Posts

* Android * [HTTP communication_2] HTTP communication with Flask (hit WebAPI [GET, POST])
HTTP communication with Python
GET / POST communication by Flask (also about CORS support)
Compare HTTP GET / POST with cURL (command) and Python (programming)
Get, post communication memo in Python
Post bulletin board creation with flask
POST variously with Python and receive with Flask
(For myself) Flask_3 (form, POST and GET)
If you get lost with HTTP redirects 301 and 302