MyEnigma

とある自律移動システムエンジニアのブログです。#Robotics #Programing #C++ #Python #MATLAB #Vim #Mathematics #Book #Movie #Traveling #Mac #iPhone

各プログラミング言語におけるシンプルなJSONサーバ・JSONクライアントの作り方

目次

はじめに

最近、様々な言語で作られたツールを連携するのに、

JSONファイルを使っているのですが、

myenigma.hatenablog.com

今回は、

そのJSONファイルを様々なプログラミング言語でやり取りするための

シンプルなJSONサーバ・JSONクライアントのコードを紹介したいと思います。

 

今回のサンプルコードでは、

基本的にクライアントがJSONファイルをHTTP経由で送信し、

そのサーバがそのJSONファイルを元に、

JSONファイルを返信するという用途でサンプルコードを作成します。

 

紹介するコードはすべて下記のリポジトリで公開しています。

github.com

順次、対応言語も増やしていく予定です。

 

Python

Server

基本的にデフォルトモジュールのみを使って実現できます。

"""

JSON Server with python

author: Atsushi Sakai (@Atsushi_twi)

"""

from http.server import HTTPServer, SimpleHTTPRequestHandler
from urllib.parse import parse_qs, urlparse
import json
from datetime import datetime
import math


class MyHandler(SimpleHTTPRequestHandler):

    def do_POST(self):

        # get request
        content_len = int(self.headers.get('content-length'))
        req = json.loads(self.rfile.read(content_len))
        print("request")
        print(req)

        uri = self.path
        ret = parse_qs(urlparse(uri).query, keep_blank_values=True)

        res = {}
        res["title"] = "Python JSON server"
        res["time"] = datetime.now().strftime("%Y%m%d%H%M%S")
        res["PI"] = math.pi
        print("response")
        print(res)

        ret = json.dumps(res)

        body = bytes(ret, 'utf-8')
        self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-length', len(body))
        self.end_headers()
        self.wfile.write(body)


def main():
    host = 'localhost'
    port = 8000
    httpd = HTTPServer((host, port), MyHandler)
    print('serving at port', port)
    httpd.serve_forever()

    print(__file__ + " start!!")


if __name__ == '__main__':
    main()

Client

こちらもデフォルトモジュールのrequestsを使いました。

"""

JSON Client with python

author: Atsushi Sakai (@Atsushi_twi)

"""

import requests
import json


def main():

    headers = {"content-type": "application/json"}
    url = "http://localhost:8000"

    obj = {"Type": "python json client", 123: 123}
    json_data = json.dumps(obj)
    print("request:")
    print(json_data)
    response = requests.get(url, headers=headers, data=json_data)

    res = response.json()
    print("response:")
    print(res)


if __name__ == '__main__':
    main()

Julia

Server

JSONサーバではHttpのServer用に

HttoServerモジュールと、

github.com

JSONパーサとして、JSONモジュールを

github.com

使用しています。

#
# JSON Server with julia
#
# author: Atsushi Sakai
#

using HttpServer
using JSON

function response_json(req)
    println("json requested!!")

    # Parse input json 
    jreq=JSON.parse(String(req.data))
    println("request:")
    println(jreq)

    jres = Dict("title"=>"Julia JSON server", "PI" => pi)
    jres["time"] = Dates.format(Dates.now(), "yyyymmddHHMMSS")
    println("response:")
    println(jres)

    return JSON.json(jres)
end


function main()
    println(PROGRAM_FILE," start!!")

    http = HttpHandler() do req::Request, res::Response
        Response(response_json(req))
    end

    server = Server(http)
    host = IPv4(127,0,0,1) # localhost
    port = 8000
    run(server, host=host, port=port)
    println("serving at port", port)

    println(PROGRAM_FILE," Done!!")
end

main()

Client

クライアントでは、Requestsモジュールを

利用しています。

github.com

#
# JSON client with Julia
#
# author: Atsushi Sakai
#

using Requests

function main()

    req = Dict("Name" => "julia json request")
    println("request:")
    println(req)

    url = "http://localhost:8000"
    res = Requests.json(Requests.post(url; json = req))
    println("response:")
    println(res)

    println(PROGRAM_FILE," Done!!")
end

main()

C++

C++はデフォルト機能として、

Http serverやJSONパーサーの機能が無いので、

下記の2つのヘッダーライブラリを使いました。

Client

//
// Json http client in C++
//
// Author: Atsushi Sakai
//

#include <iostream>
#include "../cpp-httplib/httplib.h"
#include "../json/single_include/nlohmann/json.hpp"

using namespace std;
using json = nlohmann::json;

int main(void){
    cout<<"c++ Json client start !!"<<endl;

    // Create request json
    map<string, string> c_map { {"Name", "request_from_cpp_client"},
                                {"Test", "test"} };
    json j_map(c_map);
    string sjson = j_map.dump();
    cout << "Request:" << endl;
    cout << sjson << endl;

    httplib::Client cli("localhost", 8000);
    auto res = cli.Post("/", sjson,  "application/json");

    if (res && res->status == 200) {
        cout << "Response:" << endl;
        auto jres = json::parse(res->body);
        for (json::iterator it = jres.begin(); it != jres.end(); ++it) {
            cout << it.key() << " : " << it.value() << endl;
        }
    }

}

Server

//
// Json http server in C++
//
// Author: Atsushi Sakai
//

#include <iostream>
#include "../cpp-httplib/httplib.h"
#include "../json/single_include/nlohmann/json.hpp"

using namespace std;
using json = nlohmann::json;

int main(void){
    cout<<"c++ Json server start !!"<<endl;
    httplib::Server svr;

    svr.Post("/", [](const httplib::Request& req, httplib::Response& res) {
        cout<<"request"<<endl;
        cout<<req.body<<endl;
        map<string, string> c_map { {"Name", "response_from_cpp_server"},
                                    {"Test", "test2"} };
        json j_map(c_map);

        res.set_content(j_map.dump(), "application/json");
    });

    svr.listen("localhost", 8000);
}

curl

Client

curlをシンプルなJSONクライアントとして使うことができます。

RequestのJSONを引数に入れる場合は下記のようにjsonリクエストを送信できます。

curl -X GET -H "Content-Type: application/json" -d '{"Name":"json request"}' localhost:8000

-XでHTTPのメソッドを指定し、

myenigma.hatenablog.com

-Hでアプリケーションタイプをjsonとします。

そして、-dでリクエストのJSONを指定し、

最後にリクエスト先のURLとポートを指定する形です。

サーバからのレスポンスは、標準出力に表示されます。

 

ファイルとして保存されたjsonファイルを使う場合は、

$ curl -X POST -H "Content-Type: application/json" -d @request.json localhost:8000

のように@の後にjsonファイル名を入れればOKです。

 

参考資料

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

myenigma.hatenablog.com

 

MyEnigma Supporters

もしこの記事が参考になり、

ブログをサポートしたいと思われた方は、

こちらからよろしくお願いします。

myenigma.hatenablog.com