14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

*Android*【HTTP通信_1】WebAPIを叩いてみる[GET, POST]

Last updated at Posted at 2020-09-02

はじめに

こんにちは.今回は,AndroidでWebAPIを叩いてみましょう.初めてWebAPIを叩く方でも読めるように書いていきます.WebAPIを叩く方法はいろいろありますが,Javaの標準ライブラリであるHttpURLConnectionを使用します.面倒な設定などは何もなく,WebAPIを叩くために使用するのであればオーソドックスな方法だと思います.

WebAPIを叩くと戻り値としてJSONを受け取ることになりますが,AndroidではJSONを整形して画面に出力するのが難しいので,curlコマンドを使いつつ,Androidの方を実装していきます.WebAPIを使う場合,curlコマンドに関しては使えた方がかなり作業が楽になると思います.

前提

開発環境は以下の通りです.
*Android Studio 4.0.1
*targetSdkVersion 28
*Google Nexus 5x

curlコマンド
*Ubuntu 20.04 LTS (WSL 2)

なぜWebAPIを使用するか

音楽の歌詞アプリを作りたい場合や翻訳アプリを作ることを考えます.リアルタイムに増えていく音楽の歌詞のデータを集める,データを集めて翻訳機能を作るというのは時間と手間がかかります.自分で作るのが難しい場合,ライブラリを使用すると思います.標準ライブラリ,外部ライブラリを探しても見つからない場合にどうするか.また歌詞のようにリアルタイムに変わっていくデータを扱いたい場合や,プログラミング言語に依存しないライブラリを使用したい場合にどうするか.WebAPIを探すべきです.

WebAPIは,言語に依存しない,データベースと連携している場合が多いためリアルタイムなデータ・莫大なデータを扱うのが得意といった特徴があります.HTTP通信を使用するためインターネット接続が前提ですが,Androidの場合,インターネットには常時接続できる状況が当たり前なので,WebAPIを使用してアプリを作っても問題ないです.なお,WebAPIがメンテナンスにより一時的に使用できない,仕様が変更される場合には注意が必要です.

WebAPIの使い方

厳密に説明するとわかりにくくなるので各用語の意味に関しては少し曖昧にしつつざっくり説明すると,WebAPIとは,Webサービスにおいて,開発者がプログラムからアクセスできるように許可された部分,インタフェースを指しています.WebAPIにプログラムからアクセスすることをリクエストと呼び,リクエストの結果が返ってくることをレスポンスと呼びます.リクエストを送るには,URLとHTTPメソッドを指定する必要があります.HTTPメソッドは,最も基本的なGETPOSTを使用します.具体的にどのようにリクエストを送るのか,レスポンスはどのようなものになるか,以下のとおりです.

リクエスト

URL HTTPメソッド
http://example.com/api/get GET
http://example.com/api/post POST

レスポンス

{
    "name": "foge"
}

このように,リクエストすると,レスポンスはJSONという形式で返ってきます.GETメソッドはおもにデータの取得に使い,POSTメソッドはおもにリクエストにデータを含めて送信したい場合に使用します.

どのWebAPIを使用するか

  • HTTP通信をテストする手軽な方法としてhttpbinのHPを使用する方法があります.通常WebAPIを使うには,登録やAPIキーの取得が必要ですが,httpbinのHPではそれらを必要としません.登録なしにHTTP通信を試すことができます.今回はこれを使用します.
  • 今回の記事では解説しませんが,登録やAPIキーの取得に関してもやってみたい場合は,APIキーの取得が簡単なOpenWeatherMapを利用すると良いと思います.東京の現在の天気を取得するといったことは,様々なWebページで解説されているので簡単に試せると思います.

httpbinについて

http://httpbin.orgというURLの後ろに決められたパラメータを付与することで,様々なテストが行えます.今回は,以下の機能を使用します.

機能 URL
IPアドレスの取得 http://httpbin.org/ip
GETリクエストのテスト http://httpbin.org/get
POSTリクエストのテスト http://httpbin.org/post

curlコマンド

Windowsでcurlコマンドを使用したい場合は,WSL2をインストールするか,Windows用のcurlコマンドをインストールしてください.WSL2は,WindowsでLinuxの環境を使う最も簡単な方法なので,簡単に設定できます.ここではインストールの方法に関しては触れません.
curlコマンドは様々な用途で使えますが,HTTPリクエストをする際によく使われます.では,httpbinを使用して実際にWebAPIを叩いてみます.

IPアドレスの取得,GETリクエストのテストは,GETメソッドを用います.curlコマンドでは,オプションを何もつけない場合,GETリクエストを行います.


  • IPアドレスの取得

リクエスト

curl http://httpbin.org/ip

レスポンス

{
  "origin": "111.111.111.111" # ipアドレスは個々で違う
}

  • GETリクエストのテスト

リクエスト

curl http://httpbin.org/get

レスポンス

{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.68.0",
    "X-Amzn-Trace-Id": "Root=1-5f4f2fa5-80f8b602a2eec73861aa12e8"
  },
  "origin": "111.111.111.111",
  "url": "http://httpbin.org/get"
}

  • POSTリクエストのテスト

POSTリクエストを行うには,curlコマンドのオプション-XでHTTPメソッドを指定します.-d で、POSTリクエストに含めるデータを記述できます.httpbinでは,戻り値の"form"にリクエストの際に含めたデータがセットされます.JSONを送信する場合は,Content-Typeの指定が必要である.リクエストヘッダのオプション-Hを用いる.

リクエスト

curl -X POST -H 'Content-Type: application/json' -d "name=foge&type=fogefoge" http://httpbin.org/post

レスポンス

{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "name": "foge"
    "type": "fogefoge"
  },
  "headers": {
    "Accept": "*/*",
    "Content-Length": "9",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.68.0",
    "X-Amzn-Trace-Id": "Root=1-5f4f32d3-65c03ae0882434bae32b8070"
  },
  "json": null,
  "origin": "111.111.111.111",
  "url": "http://httpbin.org/post"
}

AndroidでWebAPIを叩く

Androidでは,curlコマンドのように簡単にレスポンスの結果を整形して表示することができません.curlコマンドを使うことで適切なURLを指定できているかどうか,正しい出力ができているかどうかを確認しつつ,AndroidでWebAPIを叩く,という風にするのが良いと思います.今回は,上で実行したcurlの結果を使いつつ,Androidで必要な情報を取得したいと思います.

まず,インターネットに接続するため,AndroidManifest.xmlに以下のように記述します.

<uses-permission android:name="android.permission.INTERNET"/>

HttpURLConnection

通信を開始する前にいくつかの接続設定を行う必要があります.以下の表にまとめています.

接続設定 説明
接続タイムアウト connectメソッドで接続にかかってもよい時間の制限.
読み取りタイムアウト データ取得にかかった時間(リクエストを行いレスポンスが返るまでの時間)
User-Agent リクエストを行うソフトウェアやOS等の情報を格納(こちらがわかりやすい)
Accept-Language クライアントがどの言語を理解できるか、どの種類のロケールが推奨されるかを示す
HTTPメソッド サーバにどんな操作をしてほしいか伝えるためのもの
リクエストボディの送信許可 リクエストボディにデータを格納して送信する許可
レスポンスボディの受信許可 レスポンスボディに格納されたデータを受信する許可

では,実際にHttpURLConnectionを使ってHTTP通信を行うプログラムを示します.HttpURLConnectionはUIスレッドでは実行できないので,別スレッドを作成して実行する必要があります.
まず,IPアドレスを取得するためにGETリクエストをします.

public String getAPI(){
    HttpURLConnection urlConnection = null;
    InputStream inputStream = null;
    String result = "";
    String str = "";
    try {
        URL url = new URL("http://httpbin.org/ip");
        // 接続先URLへのコネクションを開く.まだ接続されていない
        urlConnection = (HttpURLConnection) url.openConnection();
        // 接続タイムアウトを設定
        urlConnection.setConnectTimeout(10000);
        // レスポンスデータの読み取りタイムアウトを設定
        urlConnection.setReadTimeout(10000);
        // ヘッダーにUser-Agentを設定
        urlConnection.addRequestProperty("User-Agent", "Android");
        // ヘッダーにAccept-Languageを設定
        urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
        // HTTPメソッドを指定
        urlConnection.setRequestMethod("GET");
        //リクエストボディの送信を許可しない
        urlConnection.setDoOutput(false);
        //レスポンスボディの受信を許可する
        urlConnection.setDoInput(true);
        // 通信開始
        urlConnection.connect();
        // レスポンスコードを取得
        int statusCode = urlConnection.getResponseCode();
        // レスポンスコード200は通信に成功したことを表す
        if (statusCode == 200){
            inputStream = urlConnection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
            // 1行ずつレスポンス結果を取得しstrに追記
            result = bufferedReader.readLine();
            while (result != null){
                str += result;
                result = bufferedReader.readLine();
            }
            bufferedReader.close();
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    // レスポンス結果のJSONをString型で返す
    return str;
}

次に,POSTリクエストをします.

public String postAPI(){
    HttpURLConnection urlConnection = null;
    InputStream inputStream = null;
    OutputStream outputStream = null;
    String result = "";
    String str = "";
    try {
        URL url = new URL("http://httpbin.org/post");
        // 接続先URLへのコネクションを開く.まだ接続されていない
        urlConnection = (HttpURLConnection) url.openConnection();
        // リクエストボディに格納するデータ
        String postData = "name=foge&type=fogefoge";
        // 接続タイムアウトを設定
        urlConnection.setConnectTimeout(10000);
        // レスポンスデータの読み取りタイムアウトを設定
        urlConnection.setReadTimeout(10000);
        // ヘッダーにUser-Agentを設定
        urlConnection.addRequestProperty("User-Agent", "Android");
        // ヘッダーにAccept-Languageを設定
        urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
        // HTTPメソッドを指定
        urlConnection.setRequestMethod("POST");
        //レスポンスボディの受信を許可する
        urlConnection.setDoInput(true);
        // リクエストボディの送信を許可する
        urlConnection.setDoOutput(true);
        // 通信開始
        urlConnection.connect();
        // リクエストボディの書き込みを行う
        outputStream = urlConnection.getOutputStream();
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"));
        bufferedWriter.write(postData);
        bufferedWriter.flush();
        bufferedWriter.close();
        
        // レスポンスコードを取得
        int statusCode = urlConnection.getResponseCode();
        // レスポンスコード200は通信に成功したことを表す
        if (statusCode == 200){
            inputStream = urlConnection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            // 1行ずつレスポンス結果を取得しstrに追記
            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();
    }
    // レスポンス結果のJSONをString型で返す
    return str;
}

JSONの処理

上で述べたHTTP通信の結果,JSONを文字列として取得できます.文字列からJSONのオブジェクトを生成し,中身を取り出します.


GETリクエストの戻り値からIPアドレスを取り出す

// GETリクエスト用関数の戻り値を取得.上のGETリクエストの実装を参照.
response = getAPI();
// 文字列からJSONオブジェクトを生成し,これをルートとする.
JSONObject rootJSON = new JSONObject(response); 
// curlでhttp://httpbin.org/ipにリクエストしたときの出力結果を参照
// ルート直下の"origin"というkeyのvalue(文字列)を取得
ip = rootJSON.getString("origin");

POSTリクエストの戻り値からリクエストボディに設定した値を取り出す
curlコマンドでPOSTリクエストを行った出力結果から,リクエストボディに設定した値は"form"に格納されているのを確認できる."form"に格納されているリクエストボディの値を取り出す.

// POSTリクエスト用関数の戻り値を取得.上のPOSTリクエストの実装を参照.
response = getPOST();
// 文字列からJSONオブジェクトを生成し,これをルートとする.
JSONObject rootJSON = new JSONObject(response);
// ルート直下の"form"JSONObjectを取得する
JSONObject formJSON = rootJSON.getJSONObject("form");
// "form"JSONObject直下の"name"keyと"type"keyの値(文字列)を取得する
nameAndType = formJSON.getString("name") + "/" + formJSON.getString("type");

以上を踏まえて,サンプルコードを示す.

サンプルコード

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>
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.Locale;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();
    private Button button;
    private Button button2;
    private TextView textView;
    private TextView textView2;
    private String urlIpText = "http://httpbin.org/ip";
    private String urlPostText = "http://httpbin.org/post";
    private String ip = "";
    private String nameAndType = "";

    @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);
                            ip = rootJSON.getString("origin");
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                textView.setText(ip);
                            }
                        });
                    }
                });
                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);
                            JSONObject formJSON = rootJSON.getJSONObject("form");
                            nameAndType = formJSON.getString("name") + "/" + formJSON.getString("type");
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                textView2.setText(nameAndType);
                            }
                        });

                    }
                });
                thread.start();
            }
        });
    }

    public String getAPI(){
        HttpURLConnection urlConnection = null;
        InputStream inputStream = null;
        String result = "";
        String str = "";
        try {
            URL url = new URL(urlIpText);
            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();
            String postData = "name=foge&type=fogefoge";
            urlConnection.setConnectTimeout(10000);
            urlConnection.setReadTimeout(10000);
            urlConnection.addRequestProperty("User-Agent", "Android");
            urlConnection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);
            urlConnection.connect();
            outputStream = urlConnection.getOutputStream();
            BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, "utf-8"));
            bufferedWriter.write(postData);
            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;
    }

}
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:text="Hello World!"
        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:text="Hello World!"
        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>

参照してもらいたいページ

14
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?