Kuzunoha-NEのブログ

プログラミングなどの勉強をしてます

【Node.js】WebAPIを受け取ってみる。

こんばんは葛の葉です。

さて、簡単なWebAPIを作成し、Javascriptで値を受け取るようにしてみます。

pythonでWebAPIをつくる

# app.py
from flask import Flask, request, jsonify
app = Flask(__name__)

@app.route('/')
def index():
    data = {
        'status': 'ok',
        'message': 'Hello'
    }
    return jsonify(data)

@app.route('/test')
def test():
    if request.args.get('name'):
        name = request.args.get('name')
    else:
        name = 'Nanashi'
    data = {
        'status': 'ok',
        'message': f'Hello! {name}! How are you?'
    }
    return jsonify(data)

flaskについては当ブログでも結構扱ってきたから、あんまり説明しなくてもよいかな、と思っています。jsonifyは引数で受け取った辞書型をJSONに変換し、さらにHttpレスポンスのContent-Typeをapplication/jsonにしてくれるものです。上記のPythonプログラムをapp.pyとして作成し、flask runとコマンドを叩いて実行すると以下のようになります。

$ flask run
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

別のターミナルを開いてcurlを使ってレスポンスを受け取ってみます。

// ルート直下へGetリクエスト
$ curl http://127.0.0.1:5000
{"message":"Hello","status":"ok"}

// テストルートへGetリクエストで、パラメータなし
$ curl -G "http://127.0.0.1:5000/test"
{"message":"Hello! Nanashi! How are you?","status":"ok"}

// テストルートへGetリクエストで、パラメータあり
$ curl -G "http://127.0.0.1:5000/test?name=kuzunoha"
{"message":"Hello! kuzunoha! How are you?","status":"ok"}

$ curl -G "http://127.0.0.1:5000/test?name=albatross"
{"message":"Hello! albatross! How are you?","status":"ok"}

$ curl -G "http://127.0.0.1:5000/test?name="
{"message":"Hello! Nanashi! How are you?","status":"ok"}

とまぁこんな感じで簡素なWebAPIが作れました。

Nodeのaxiosというモジュールをつかう

Node.JsにはaxiosというHttpリクエストを投げて受け取るモジュールがあります。ご多分の通り、Node.jsは非同期I/Oなので、普通にリクエストを投げるとレスポンスが帰ってくる前に次のコードが実行されちゃいます。そこでPromiseというオブジェクトを用いることがあるわけですが、このaxiosはHttpRequestをPromiseベースで実行してくれるモジュールになります。

github.com

使い方はこんな感じ。(typescriptです)

// webapp.ts
import axios from "axios";

axios.get('http://localhost:5000/')
.then(function(response) {
    console.log(response.data);
}).catch(function(error){
    console.log(error)
})

axios.get(URL)は見ての通りgetメソッドでURLを取得しにいっています。さて、.thenというPromiseオブジェクトっぽいのが出てきました。

axios.get(URL).then(コールバック関数1).catch(コールバック関数2)

axios.get()が正常に終了したとき.then内のコールバック関数1が実行されます。このときの引数をresposeとしていますが、axiosが受け取ってきたHttpResponseになります。axios.get()が失敗した際はそのerrorを.catch内のコールバック関数2に渡し、実行します。

コンパイルすると以下の感じ。

"use strict";
exports.__esModule = true;
var axios_1 = require("axios");
axios_1["default"].get('http://localhost:5000/')
    .then(function (response) {
    console.log(response.data);
})["catch"](function (error) {
    console.log(error);
});

コンパイルされたwebapp.jsをnodeで実行すると以下のようになります。

$ node webapp.js
{ message: 'Hello', status: 'ok' }

webapp.tsの3行目をaxios.get('http://localhost:4000/')にしてコンパイルして実行すると、そのポートにWepアプリがなければエラーが返ります。

$ node webapp.js
{ Error: connect ECONNREFUSED 127.0.0.1:4000
    at Object._errnoException (util.js:1022:11)
    at _exceptionWithHostPort (util.js:1044:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1198:14)
  code: 'ECONNREFUSED',
  errno: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 4000,
  config: 
   { url: 'http://localhost:4000/',
     method: 'get',
(以下省略)

getメソッドのパラメータを渡すことも可能です。

// webapp.ts
import axios from "axios";

axios.get('http://localhost:5000/test', {
    params:{
        name: "kuzunoha"
    }
})
.then(function(response) {
    console.log(response.data);
}).catch(function(error){
    console.log(error)
})

Nodeで実行すれば以下のように。

$ tsc webapp.ts 
$ node webapp.js
{ message: 'Hello! kuzunoha! How are you?', status: 'ok' }

expressで表示してみる

webapp.tsにexpressで表示してあげればもっとわかりやすくなる。

// webapp.ts
import axios from "axios";
import * as express from "express";

let app = express();

app.get('/', (req, res)=>{
    axios.get('http://localhost:5000/test', {
        params:{
            name: "kuzunoha"
        }
    })
    .then(function(response) {
        const ret = response.data;
        res.send(ret.message);
    }).catch(function(error){
        console.log(error)
    })        
})

app.listen('3000', function(){
    console.log('listen port:3000')
})

ExpressとはWebフレームワークになります。Expressのインスタンスappとしています。

expressjs.com

tsc webapp.ts -> node webapp.jsとして実行してみてください。

$ tsc webapp.ts 
$ node webapp.js
listen port:3000

http:127.0.0.1:3000/にアクセスすると以下のようになります。

f:id:Kuzunoha-NE:20190829211837p:plain
Hello! kuzunoha! How are you?と表示される

app.get(文字列, コールバック関数)は文字列でアクセスするとコールバック関数が実行されるというものです。アクセスが正常であればコールバック関数に受け取ったHttpRequestとこれからクライアントに返すResponseが引数に渡されます。http://127.0.0.1:3000にアクセスしたタイミングで、axios.get()以下が実行されます。

axiospythonflaskアプリケーションに飛んで、情報を取得してきます。その取得してきた情報をhttp://127.0.0.1:3000にアクセスしたクライアントに返しています。

とこのようにすることで、Javascriptは表示に専門、Pythonは内部処理に専門、と分けることができるのです。