Processingで作るWeb API

はじめに

どうもSaKuです.
これは, FUN Advent Calendar 2019 11日目の記事です. adventar.org 本来はGraphQLの話を書くつもりだったんですが, なんか未来大っぽさが足りなかったので, みんな大好きProcessingの話に変更しました. 大学のProcessingの授業で満足できなかった人やスケジューラーの授業で何実装するか迷っている人がいましたら, 参考にしてみてください!
あと, 間違ったことを書いているかもしれませんのでお手柔らかにお願いします...

Processingとは

2年生に進級する際にProcessingを記憶から消し去った人のために解説.

Processing is a flexible software sketchbook and a language for learning how to code within the context of the visual arts. Since 2001, Processing has promoted software literacy within the visual arts and visual literacy within technology. (以下略)
出典: https://processing.org より

どうやら視覚的な表現を柔軟にかけるプログラミング言語らしい.

今回やること

前置きが長くなりましたが今回やることは, 視覚的な表現に長けたProcessingを使って視覚的な表現を一切使わない簡単なWeb APIを作っていこうと思います.

※ほぼコードの解説なので, ソースコードだけみたい人はgithubに上げましたのでそちらを読んでみてください.

github.com

サーバーの実装

公式リファレンスを眺めてたらprocessing.net.*なるものがあったのでこれを使いました.

import processing.net.*;
Server server;

int port = 9000;

void setup() {
  server = new Server(this, port);
  println("Launch Server: " + server.ip() + ":" + port);
}

void draw() {
}

実行してみると以下のようにIPとPortがコンソール画面に表示されると思います.

Launch Server: 127.0.0.1:9000

クライアントの状態を受け取る

drawに実装していきます.

void draw() {
  Client client = server.available();

  if (client != null) {
    if (client.available() > 0) {
      // ここにリクエストに対する処理をかく
    }
  }
}

クライアントからリクエストが投げられていない場合は最初のif文で, リクエストが飛んできたけどサーバ側が使用可能な情報がない場合は2つ目のif文で弾くように実装しています.

クライアントからのリクエストに対してHTMLを返してみる

まず, レスポンスとして返すHTMLを作成します.
作成したHTMLファイルはスケッチアップのコードがあるディレクトリ内のhtml/hello.htmlに保存しておきます.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
</head>
 
<body>
    <h1>Processingで作るWeb API</h1>
    <h2>Processingで作るWeb API</h2>
    <h3>Processingで作るWeb API</h3>
</body>
</html>

次に, クライアントからのリクエストに対する処理を実装していきます.

String[] request;
void draw() {
  Client client = server.available();
  if (client != null) {
    if (client.available() > 0) {
      request = trim(split(client.readString(), '\n'));

      if (RequestCheck("GET", "/html")) HTMLHandler(client);
      client.stop();
    }
  }
}

boolean RequestCheck(String method, String path) {
  return (trim(split(request[0], ' '))[0].equals(method)
    && trim(split(request[0], ' '))[1].equals(path))? true: false;
}

void HTMLHandler(Client client) {
  String[] html = loadStrings( "html/hello.html" );
  // 初期応答行
  client.write("HTTP/1.1 200 OK\n");
  // (確か) ヘッダ行
  client.write("Content-Type: text/html\n");
  client.write("\n");
  // Body
  for (int i = 0; i < html.length; i++) {
    client.write(html[i]);
  }
}

読めばわかると思いますが一応解説.
- RequestCheck: リクエストの初期要求行をこねこねしてメソッド名とパスをとってきて比較しています.
- HTMLHandler: クライアントからのリクエストに対してレスポンスの処理をしています.
先ほど作成したHTMLファイルを読み込んで, レスポンスに書き込んでいる感じですね.

ブラウザで叩いてみると以下のように先ほど作成したHTMLが表示されていると思います. f:id:SaKu2110:20191210230400p:plain

JSONを受け取って返してみる

HTML返すところまでで十分な気がしますが, なんか物足りないのでJSONのやりとりもできるようにしてみます.
疲れてきたので, リクエストからとってきたJSONをそのまま返すようにしました.

void draw() {
  Client client = server.available();

  if (client != null) {
    if (client.available() > 0) {
      request = trim(split(client.readString(), '\n'));

      if (RequestCheck("GET", "/html")) HTMLHandler(client);
      if (RequestCheck("POST", "/json")) JSONHandler(client);
      client.stop();
    }
  }
}

void JSONHandler(Client client) {
  String json = "";
  for (int i = 11; i < request.length; i++) json += request[i];
  client.write("HTTP/1.1 200 OK\n");
  client.write("Content-Type: application/json\n");
  client.write("\n");
  client.write(json);
}

Postmanで叩いてみると見事JSONが返ってきました!やったね!!!!!!!!!! f:id:SaKu2110:20191210232015p:plain

まとめ

描画に特化したプログラミング言語でもやろうと思えば結構行けるなーと思いました.
他言語のフレームワークを利用してゴリゴリ開発するのもいいですが, あえて普段書かない言語や不向きな言語で開発するのも新鮮味があって良いかもしれません. (楽しかった)

ほんとはコンテナ化までしたかったのですがX11 転送周りで盛大にコケてしまい, 実装できなかったのが残念です...

初めてブログを書いたので, まとまっておらず読みにくかったかもしれませんが最後まで読んでくださりありがとうございます! m( _ )m
明日は, hacuskさんと
leo_isaacさんですお楽しみに!