20191128のNode.jsに関する記事は10件です。

Node.jsで、ファイルから1行ずつ読み込むためのreadlineモジュール

注意

この記事は初心者視点でザックリとした説明をしています。正確性に欠ける可能性がございますが、ご了承ください。「明らかに違うよ」ということがありましたら、ご指摘くださると幸いです。

Node.jsでファイルに1行ずつ書き込みたい。

Node.jsを使う際、.txtファイルや.csvファイルを一行ずつ読み込みたい場合がありました。
そんな時に使えるのがreadlineモジュールです。Node.jsで標準に備えられています。

readlineモジュールの使い方

まずは以下のように、ファイルに書きます。

index.js
'use strict';
//モジュールの読み込み
const fs = require('fs');
const readline = require('readline');

//readstreamを作成
const rs = fs.createReadStream('./input.csv');
//writestreamを作成
const ws = fs.createWriteStream('./output.csv');

//インターフェースの設定
const rl = readline.createInterface({
//読み込みたいストリームの設定
  input: rs,
//書き出したいストリームの設定
  output: ws
});

//1行ずつ読み込む設定
rl.on('line', (lineString) => {
  //wsに一行ずつ書き込む
  ws.write(lineString + '\n');
});
rl.on('close', () => {
  console.log("END!");
});

ストリームの作成

readlineを利用するときは、単独では使えずストリームと組み合わせて使わなければいけません。そのため、以下のように読み込みストリームと書き込みストリームを作成しています。

//readstreamを作成
const rs = fs.createReadStream('./input.csv');
//writestreamを作成
const ws = fs.createWriteStream('./output.csv');

インターフェースの設定

以下の部分では、readlineでどのストリームを読み込むのか、どのストリームに書き出すのかの設定をしています。

//インターフェースの設定
const rl = readline.createInterface({
//読み込みたいストリームの設定
  input: rs,
//書き出したいストリームの設定
  output: ws
});

1行ずつ読み込んでいく設定

最後に1行ずつ読み込んでいく設定です。
'line'イベントが起きたら(1行読み込まれたら)、その行がlineStringに代入されます、そしてws(書き込みストリーム)に書き込まれていきます。
そのままだと、ws(書き込みストリーム)に設定したファイルの最初の行に、読み込んだすべての行が書き込まれてしまうので、以下のように改行"\n"をつけています。

//1行ずつ読み込む設定
rl.on('line', (lineString) => {
  //wsに一行ずつ書き込む
  ws.write(lineString + '\n');
});

実行してみる

例えば、以下のファイルを1行ずつ読み込みたいとします。

input.csv
ほげ
ほげほげ
ほげほげほげ
ほげほげほげほげ
ほげほげほげほげほげ
ほげほげほげほげほげほげ
ほげほげほげほげほげほげほげ
ほげほげほげほげほげほげほげほげ

以下のようにJSファイルを実行します。

console
$ node index.js
> END!

すると、書き込みたいファイルに以下のように、一字一句違わずに書き込まれているはずです。

output.csv
ほげ
ほげほげ
ほげほげほげ
ほげほげほげほげ
ほげほげほげほげほげ
ほげほげほげほげほげほげ
ほげほげほげほげほげほげほげ
ほげほげほげほげほげほげほげほげ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

toio と Unity の連携

はじめに

これは「toio™(ロボットトイ | toio(トイオ)) Advent Calendar 2019」の1日目の記事になります。

この記事ではUnityとtoioの連携方法を記します。
以下の記事・サイトを参考にしました。

toio.js とは

toio.js は Node.js を用いたtoio公式のライブラリです。
パソコン側からcoreCubeを動かしたり、マット上の位置を取得したり出来ます。
今回はこれを使ってマット上のcoreCubeにUnity上のCubeを連動させたいと思います。

環境

OS : MacOS High Sierra 10.13.6

下準備

Unity

Unity Hub のインストール

Unity Hub を入れます。
こちらUnityHubをダウンロードからインストーラをダウンロードできます。

unity hubを起動してインストールで最新バージョンのUnityを入れます。
このとき、Visual Studioも一緒にインストールします。
スクリーンショット 2019-11-26 15.04.54.png

UniRx

Unity Hub で新規プロジェクトを作成します。
スクリーンショット 2019-11-26 14.48.17.png

プロジェクトが開いたらAssetストアで UniRx をダウンロード、インポートします。
すると、Assetsフォルダ下にPluginsフォルダができ、その中にUniRxが入ります。
スクリーンショット 2019-11-26 15.31.22.png

C# websocketライブラリ

こちらからライブラリをダウンロードして解凍します。
スクリーンショット 2019-11-28 21.31.12.png

中にある websocket-sharp.csproj をVisualStudioで開きビルドすると bin/Debug 下に websocket-sharp.dll が出来ます。
スクリーンショット 2019-11-28 21.30.09.png

この websocket-sharp.dll を先ほど作成したプロジェクトの Assets/Plugins に入れます。
スクリーンショット 2019-11-26 15.51.16のコピー.png

これでUnity側の下準備は完了です。

toio.js

brew install yarn

yarn に関しては公式では npm で入れていますが、

npm install -g yarn

私は以下のように brew を使いました。

brew install yarn 

権限が必要だったり入れ難かった覚えがありましたが、なんかと入れたようです。
良くないことをしたかも知れません。

toio.js

次に toio の github から toio.js を clone します。
公式曰く、以下のコマンドでパッケージのbuildまで済みます。
yarn example:hogehoge でサンプルプログラムが動きます。

git clone https://github.com/toio/toio.js.git
cd toio.js
yarn install
yarn build
yarn example:keyboard-control

coreCubeの電源を入れて接続され方向キーで動いたらオッケーです。
僕は接続されなかったのでパソコンを再起動したら動きました。

実装

Unity側

SceneにCreateから3D Object/Cubeを置きます。
またCreateからUI/Buttonを置いておきます。

GameViewでみるとこんな感じになると思います。
スクリーンショット 2019-11-28 21.10.24.png

Cube に Add Component/NewScript でPositionSyncというスクリプトをつけます。
以下、@nmxi さんの記事*から拝借したコードを改変して書いた中身です。

PositionSync.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using WebSocketSharp;
using UniRx;

public class PositionSync : MonoBehaviour
{

    [SerializeField] private string _serverAddress;
    [SerializeField] private int _port;

    [SerializeField] private SyncPhase _nowPhase;

    private GameObject tA;
    private WebSocket ws;
    string message = "";
    string messageA = "";

    public float span = 0.5f;

    public enum SyncPhase
    {
        Idling,
        Syncing
    }

    private void Awake()
    {
        tA = GameObject.Find("Cube");
        _nowPhase = SyncPhase.Idling;

    }

    void Update()
    {
        string[] m = message.Split(',');

        switch (m[0])
        {
            case "A":

                if (message != messageA)
                {
                    ////サイズの変更
                    //マット
                    //559mm 410points 
                    //toioコアキューブ
                    //31.8mm about 23.3point

                    tA.transform.position = new Vector3(-(float.Parse(m[2]) - 250.0f) / 10.0f, tA.transform.position.y, -(float.Parse(m[1]) - 250.0f) / 10.0f);
                    tA.transform.rotation = Quaternion.Euler(0, float.Parse(m[3]), 0);
                }
                messageA = message;
                //Debug.Log(m);
                break;
        }


    }
    /// <summary>
    /// Get Down Start Sync Button
    /// </summary>
    public void OnSyncStartButtonDown()
    {
        var ca = "ws://" + _serverAddress + ":" + _port.ToString();
        Debug.Log("Connect to " + ca);
        ws = new WebSocket(ca);

        //Add Events
        //On catch message event
        ws.OnMessage += (object sender, MessageEventArgs e) => {
            message = e.Data;

        };

        //On error event
        ws.OnError += (sender, e) => {
            Debug.Log("WebSocket Error Message: " + e.Message);
            _nowPhase = SyncPhase.Idling;
        };

        //On WebSocket close event
        ws.OnClose += (sender, e) => {
            Debug.Log("Disconnected Server");
        };

        ws.Connect();

        _nowPhase = SyncPhase.Syncing;
    }

    public void OnChangedTargetTransformValue(Vector3 pos)
    {
        if (_nowPhase == SyncPhase.Syncing)
        {
            //ws.Send(pos.ToString());
            //ws.Send("1");
        }
    }
}

Cube にある PositionSync (Script)の欄に
Server Address には "localhost"、Port には "8080"を入れて置きます。
スクリーンショット 2019-11-28 21.05.17.png

先ほど置いたButtonのOn Click()に Cube/PositionSync/OnSyncStartButtonDown() を追加します。
スクリーンショット 2019-11-28 21.12.27.png

toio.js側

toio.js/projectsフォルダを作成し、その中にスクリプトを置きます。
今回はtoio公式のサンプルと@nmxi さんの記事*から拝借したコードを悪魔合体して以下のスクリプトを生成しました。

マット上におけるcoreCubeの絶対位置をUnityに送るプログラムです。

toio_node.js
const { NearestScanner } = require('@toio/scanner')

var WebSocketServer = require('ws').Server

var wss = new WebSocketServer({
    port: 8080
});

var cube;

async function main() {
  // start a scanner to find nearest cube
  cube = await new NearestScanner().start()

  // connect to the cube
  await cube.connect()
}

main()

wss.on('connection', function(ws) {

    //position-idに変化があった時
    //移動、回転
    //toioPositionを更新する
    cube.on('id:position-id', data => {
        ws.send("A,"+data.x+","+data.y+","+data.angle)

    })
    //マットから離れた時
    cube.on('id:position-id-missed', () => {
      // ws.send('Position Miss!');
    })
});

実行

1.coreCube の電源を入れます。

2.toio_node.js を実行します。(少しして coreCube から音がします。)

 cd projects
 node toio_node.js

3.Unity のプロジェクトを Run します。

4.GameView 上で Button をクリックします。

この状態でマットに置いた coreCube の位置が Unity の Cube に反映されれば成功です。

こんな感じ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.jsでMySQLに接続するのをDockerでやってみた

この記事は富士通クラウドテクノロジーズ Advent Calendar 2019 5日目の記事です。
4日目は @tmtms さんの MySQL Parameters を拡張した でした。

はじめに

  • ※本記事は、 Node.js超入門[第2版] のサンプルコードをDocker上で動かす趣旨のものです。 よって、書籍で言及されている階層は触れません。

はじめまして。Node.jsを勉強中の新卒エンジニアです。
配属したてホヤホヤです。
今回は Node.js超入門[第2版] を使って勉強したときの話をします。

この書籍の内容をDockerで実現しようとした経緯ですが、そのまま「Dockerを理解したかったから」です。
弊社の研修でもDockerについて触れていただいたのですが、一度教わっただけでは理解が難しいものでした。
というわけで、サンプルコードを写経するだけになりがちだった(主観です)プログラミングの本で、ついでに理解を深めようという魂胆です。

今回は、書籍の Chapter5「値とデータをマスターしよう!」の、Section5-3~5-4 で書かれている、Node.jsでDBにアクセスして情報を取得し、ブラウザに表示するプログラムを紹介します。書籍が手元にある方はぜひ確認してみてください。

環境構築

必要な環境

参考記事:

解説

  • 今回は、Node.jsもMySQLも、Dockerコンテナとして生成しています。
  • Node.jsサーバーは、 docker-compose.yml から Dockerfile を呼び出す形で書き、MySQLサーバーは docker-compose.yml 内で定義しています。
  • docker-compose.yml で指定するMySQLのDockerイメージは、MySQLのバージョンが8よりも前になるように古いものを使っています。 8以降はそのままだとNode.jsとの連携ができないようです。
  • init-mysql.sh は、ローカル環境から、データベース用のコンテナにアクセスし、テーブル作成->データ挿入までを行っています。
  • 実は、docker/db/my.cnfdocker-compose.yml の2か所で mysqld を設定しているのですが、どちらかを消すとなぜかエラーになってしまうため(!)そのままにしてあります。いい方法ががありましたら教えていただけると幸いです・・・。
  • 余談ですが、今回のコードは、いままで述べてきたものとは別のDockerfileでExpress-generatorを実行し、 docker cp でローカルにファイルをコピーしてから作成していきました。 めんどうくさいことをしたなと自分で思います。

動作確認

  • 上記のリポジトリをcloneします。
  • リポジトリに移動
  • docker-compose up -d でコンテナを立ち上げます。
  • すこし(10秒ほど)時間をおきます。(コンテナが出来上がるまで待つ)
  • ローカルで ./init-mysql.sh を実行します。
  • localhost/hello にアクセスし、 docker/db/sql/002-insert-records.sql で入れたデータが表示されていることを確認してください。
  • ↓ こんなふうに表示されます。

image.png

おわりに

まず、Node.jsについての書籍を読み、サンプルを実行してみることで、Node.jsの挙動についてざっくりと理解できるようになりました。
加えて、それらをDocker上の環境で行うことで、
いままで「VirtualBoxより軽い仮想化するアプリケーション?」という認識だったDockerについての理解も深まりました。
Linuxのコンソールの扱いも以前よりわかるようになってきました。
やっと .profile.vimrc をカスタマイズできるようになり、快適なUbuntu生活をしております。

また、試行錯誤して、調べたり人に聞いたりしていくことが学びへの近道だと実感しました。
例えば、MySQLのバージョンに関しては自分では調べきれず、先輩方の知恵をお借りしました。
ありがとうございました。

まだまだエンジニアとしては若輩者ですが、これからもっと勉強してスキルをつけ、開発をたくさんしていけたらと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DOMについて調べたことの備忘録

 DOMについて

  • Document Object Model
  • HTML や XML 文書を操作するための、たくさんの機能や規則のこと
  • DOMは階層構造をとる
  • 各要素はノードという単語を用いて表現される

ノードについて

  • ノード
  • 子ノード(children)
  • 親ノード(parent)
  • 兄弟姉妹ノード
  • ノードは、webページとプログラミング言語をつなぐ役割を持つ
  • ID名からノードを取得、操作する

JavaScript初心者でもすぐわかる!DOMとは何か?

DOMとは何か?【JavaScript初心者向けにわかりやすく説明します!】

DOMの話に戻ります

HTML要素の取得:getElementById()

  • Documentオブジェクトのメソッドである「getElementById()」が一般的らしい
  • 文字列のHTMLタグを認識できる

使用例

<body>
<p id="text">これはサンプルテキストです</p>

<script>
    var p = document.getElementById('text');

    console.log( p );
</script>
</body>

実行結果

<p id="text">これはサンプルテキストです</p>

HTML要素をJavaScriptから書き換える:innerHTMLプロパティ

  • 「innerHTML」プロパティを代入するだけ!

使用例

<div id="wrap">
    <p>これはサンプルテキストです</p>
</div>

これをinnerHTMLプロパティでp要素をh1要素に書き換える

var div = document.getElementById('wrap');

div.innerHTML = "<h1>サンプルタイトル</h1>";

console.log( div );

実行結果

<div id="wrap">
    <h1>サンプルタイトル</h1>
</div>

JavaScriptからHTML要素を作成する:createElement( )

  • もっとも簡単な方法はcreateElement()
  • 例えば「createElement('p')」と記述することで「p要素」を新規に生成
var pElement = document.createElement('p');
  • この方法で作成しても、画面に表示されないので、HTML要素をDOMに追加しなくてはならない

HTML要素を追加:appnedChild()

  • JavaScript側で生成したHTML要素をDOMに追加
var p = document.createElement('p');

//テキストを追加する
p.textContent = 'これはサンプルです';

//body要素内にp要素を配置する
document.body.appendChild( p );

実行結果

<p>これはサンプルです</p>

※ textContent()メソッドでテキストを追加

DOMが読み込まれるタイミング:onloadイベント

  • DOMによるオブジェクト化がされていないと、JavaScript側からHTMLを操作できない
  • DOMが読み込まれた後にJavaScriptが実行できるようにしなければならない
  • その中で、もっとも簡単なのがonloadイベント
dow.onload = function() {

    //ここに処理を書く

}
  • しかし複数記述すると、その都度上書きされてしまうので、上に書いたものは実行されない・・・
window.onload = function() {
//処理1
}

window.onload = function() {
//処理2
}

window.onload = function() {
//処理3
}
  • こちらの処理は一番下しか実行されない

onloadでなくaddEventListenerを使ってみる

使用例

window.addEventListener('load', function() {
//処理1
})

window.addEventListener('load', function() {
//処理2
})

window.addEventListener('load', function() {
//処理3
})
  • 第一引数にloanを書き、第二引数に実行する関数処理をかく
  • addEventListenerを使用することで、3回記述したとしても全て実行することができる

【JavaScript入門】はじめてのDOM操作・取得まとめ!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE Notifyのnpmライブラリ作ったのでサンプルソースを紹介する

はじめに

LINE Notify APIのNode.jsライブラリを作りました。
https://www.npmjs.com/package/line-notify-nodejs

使い方とサンプルソースを紹介します。

使用イメージ

Lwie2cZnxIv4eVYeEe9e1574930325-1574930375.gif

インストール

$ npm install line-notify-nodejs

使い方

簡単2STEPです。

STEP1. トークンを発行する

下記ページからトークンを発行します。

image.png

image.png

image.png

STEP2. 通知を送信する

index.js
const lineNotify = require('line-notify-nodejs')('kQnesu**********************'); // 先ほどコピーしたトークン

lineNotify.notify({
  message: 'send test',
}).then(() => {
  console.log('send completed!');
});
$ npm run index.js

これで通知が送信されます!
Lwie2cZnxIv4eVYeEe9e1574930325-1574930375.gif

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE Notifyのnpmライブラリ作ったので紹介する

はじめに

LINE Notify APIのNode.jsライブラリを作りました。
https://www.npmjs.com/package/line-notify-nodejs

使い方とサンプルソースを紹介します。

使用イメージ

Lwie2cZnxIv4eVYeEe9e1574930325-1574930375.gif

インストール

$ npm install line-notify-nodejs

使い方

簡単2STEPです。

STEP1. トークンを発行する

下記ページからトークンを発行します。

image.png

image.png

image.png

STEP2. 通知を送信する

index.js
const lineNotify = require('line-notify-nodejs')('kQnesu**********************'); // 先ほどコピーしたトークン

lineNotify.notify({
  message: 'send test',
}).then(() => {
  console.log('send completed!');
});
$ npm run index.js

これで通知が送信されます!
Lwie2cZnxIv4eVYeEe9e1574930325-1574930375.gif

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE Notifyのnpmライブラリ作った

はじめに

LINE Notify APIのNode.jsライブラリを作りました。
https://www.npmjs.com/package/line-notify-nodejs

使い方とサンプルソースを紹介します。

使用イメージ

Lwie2cZnxIv4eVYeEe9e1574930325-1574930375.gif

インストール

$ npm install line-notify-nodejs

使い方

簡単2STEPです。

STEP1. トークンを発行する

下記ページからトークンを発行します。

image.png

image.png

image.png

STEP2. 通知を送信する

index.js
const lineNotify = require('line-notify-nodejs')('kQnesu**********************'); // 先ほどコピーしたトークン

lineNotify.notify({
  message: 'send test',
}).then(() => {
  console.log('send completed!');
});
$ npm run index.js

これで通知が送信されます!
Lwie2cZnxIv4eVYeEe9e1574930325-1574930375.gif

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[kintone] node.jsで開発環境のフィールド権限を本番環境に反映する

概要

開発環境を本番環境に反映する際、フィールド権限などはアプリテンプレートでは
持ってこれないのでcli叩いてやりたかった。
kintone-cliとか便利なツールあるのでそれ使えたら使ったほうがいいと思います。
今回しか使わない捨てコードなので適当ですが

main.js
const request = require("request");

const params = {
  url: "開発用のドメイン/k/v1/field/acl.json?app=1",
  method: "GET",
  json: true,
  headers: {
    "X-Cybozu-Authorization": "ログイン名とPWをBase64エンコードしたもの"
  },
};

request(params, (err, res, body) => {
  if (err) {
    console.log('err :', err);
    return;
  }

  const Admine = "本番用ドメインのログイン名とPWをBase64エンコードしたもの";
  params.url = "本番用ドメイン/k/v1/field/acl.json"
  params.headers["X-Cybozu-Authorization"] = Admine;
  params.method = "PUT";
  params.json = {
    "app": 1,
    "rights": body.rights
  };
  request(params, (err, res, body) => {
    if (err) {
      console.log('err :', err);
      return;
    }
    console.log('body :', body);
  });
});
$ node main.js

したあとRevisionのログ流れたらOK

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ローカル環境で LINEWORKS Bot を動かす話

LINEWORKS Advent Calendar 2019 の 3日目を担当させていただきます!
どうぞよろしくおねがいしますm( )m

さっそくですが、タイトルの通りローカル環境で LINEWORKS Bot を動かす話をしたいと思います。

開発用に自由に使えるサーバを持ってない私にとって、LINEWORKS Bot を実際に動かすのに GoogleAppsScripts が便利なのでよく使っています。
ですが、Node.js が基本スキルの私にとって、GAS は Javascript に近い作りですが微妙に違ってくるので、やっぱりちゃんと Node.js のコードでテストしたい!って思うわけなのです。

ローカル環境でトーク Bot を動かすには、
1. ローカル環境に http サーバを立ててアプリケーションを動かして
2. 外部公開用の URL を取得して Bot の Callback URL に登録する

と、いう流れになりますねー。
では、さっそくやっていきますね。

ローカル環境に http サーバを立ててアプリケーションを動かす

たぶん、読んでる方々には釈迦に説法状態だと思うので、非常に恐縮なのですが。。。
Node.js には express という、すんばらごいモジュールがいらっしゃいます。(゚Д゚)ノ
知っている方は読み飛ばしていただいて結構ですよ!( ;∀;)

では、express をさくっとインストールしていきましょー。

と、その前に package.json ファイルを作ります。
このアプリケーションはこんなアプリケーションですよーってファイルです。
「わかってるよ!もうあるよ!」って方はごめんなさい。読み飛ばしてください。

以下のコマンドを実行してください。

> npm init

英語で質問されるので、ペラペラバイリンガルなあなたは適切に答えていただければ大丈夫!
英語得意じゃないので全部 Enter!(゚Д゚) それでも大丈夫!

package.json ファイルが作成されますので、中身を開いてみてください。

真ん中らへんに "start" の項目があると思うので以下のように書き換えます。

"scripts": {
  "start": "node ./app.js"
},

設定が終わったら express をインストールします。

> npm install express --save

インストールが終わったら、アプリケーションのコードを書いていきましょう!
単純に、メッセージを受け取ってコンソールに表示するだけのプログラムです。

app.js
const express = require('express');
const app = express();
const port = xxxx; // port には任意の値を入れてください。
app.listen(port);

app.post('/callback', function(req, res) {
    console.log(req.body);
});

npm start で実行してアプリケーションを起動させます!

> npm start

これで準備は OK です!
次の手順に進みましょう。

外部公開用の URL を取得して Bot の Callback URL に登録する

ローカル環境を外部公開するなんて、どうしたらいいのやらやら。
そんなとき大活躍してくれる強い味方! ngrok さんです!ヾ(´∀`)ノ

・・・なんか、モジュール紹介になってる気もしますが、これ、全部 LINEWORKS Bot を使うためですから!(^_-)-☆

ngrok さんを使えば、ローカル環境のサーバを外部公開できます!
LINEWROKS Bot の Callback URL は https でないといけないのですが、もちろん ngrok さんは https の URL を作成してくれんですよ~。ありがたい(*´Д`)

それでは、さくさくっといきましょー。
まずは、別のターミナルを起動して ngrok さんをインストールしてください。

> npm install ngrok --save

そして、あとはコードを書いて実行するだけ。

getCallbackUrl.js
const ngrok = require('ngrok');
const port = xxxx; // port には任意の値を入れてください。
ngrok.connect(port).then((ngrokUrl) => {
    console.log('bot callback URL : ' + ngrokUrl + "/callback");
});

すると、ローカル環境がサーバとなり、URL が発行されます。

> node .\getCallbackUrl.js
bot callback URL : https://ff7b9d27.ngrok.io/callback

あとはこの URL を Bot に登録すれば OK!
こんなに楽チンに https の URL が取得できちゃうなんて、ありがたいですよねー(*´Д`)

API で Callback URL を登録する

ngrok での URL はプログラムを終了すると取得しなおしになるので、その度に Bot に登録し直しになります。
次の日とか、URL 取り直してー、登録し直してー、ってやらないといけません。
めんどいっ!(゚Д゚)ノ

URL を取得したらそのまま登録しちゃえばいいんですよ!
ってなわけで、さっきのコードを改造していきます。

Callback URL を登録するのに API を使うので request-promise モジュールを先にインストールしておきます。

> npm install request-promise --save

普通の request モジュールでもいいのですが、request-promise だとエラー処理が .catch でできるので愛用しています。
インストールしたら準備は OK!
コードを書いていきましょう。

setCallbackUrl.js
const ngrok = require('ngrok');
const port = xxxx; // port には任意の値を入れてください。
const request = require('request-promise');

ngrok.connect(port).then((ngrokUrl) => {
    console.log('bot callback URL : ' + ngrokUrl + "/callback");
    const options = { // apiId,consumerKey,token,botNo はご自身のものを入力してください。
        uri: "https://apis.worksmobile.com/" + apiId + "/message/setCallback/v2",
        headers: {
            "Content-type": "application/json",
            "consumerKey": consumerKey,
            "Authorization": "Bearer " + token
        },
        json: { 
            "botNo": botNo,
            "callbackUrl": ngrokUrl + "/callback",
            "callbackEventList": ["text", "sticker"]
        }
    };
    request.post(options).then((body) =>  { console.log(body) })
        .catch((error) => { throw new Error(error) });  
});

では、実行して Callback URL を登録しましょう!(=゚ω゚)ノ

> node setCallbackUrl.js
bot callback URL : https://252b7e9b.ngrok.io/callback
{ message: 'OK', code: 200 }

200 OK をもらいましたが、念のため DeveloperConsole でも確認しましょう。
1574750764.png

ちゃんと、登録されていますね!
これで、完成です!

さぁ、Bot に話しかけてみよう

初めての方に話しかけるのは緊張しますよね!
ここはビシッと!格好よく!トークしましょう!
1574917495.png

{ type: 'message',
  source: { accountId: 'xxxxx@yyy-zzz', roomId: '26280667' },
  createdTime: 1574917451022,
  content: { type: 'text', text: 'hogehoge' } }

送ったメッセージが app.js のコンソール画面に表示されましたね。
成功です!(*'▽')やったー

おわりに

ここまでお付き合いいただきありがとうございました。

改めて、LINEWORKS Advent Calendar 2019 の3日目として参加させていただきありがとうございました。
少しはかしこまって書こうかな?とか考えていたのですが、結局いつも通りのテンションでした(=゚ω゚)
本当に申し訳なく思っておりますまる。

5日目にもエントリーしてるので、またどうぞよろしくお願いします~('ω')

ではまた!(^^)/

参考にさせていただきましたm(_ _)m

Express 公式ガイド
ngrok Documentation
LINEWORKS Developers

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js + axios で 画像をFormDataでアップロードしようとしてハマった話

やりたかったこと

Node.jsのスクリプトでローカル上の画像ファイルをmulitpart/form-dataで送信したかった。
フロント側でaxiosを使っていて楽だったのでそれを使おうと思った。

結論

const fs = require('fs')
const axios = require('axios')
const FormData = require('form-data')

const uploadImage = async ({ auth_token, imageFilePath }) => {
  const form = new FormData()
  const file = fs.createReadStream(imageFilePath)
  form.append('image_file', file)
  const config = {
    headers: {
      'X-AUTH-Token': auth_token,
      'X-API-Token': env.API_TOKEN,
      ...form.getHeaders(),  // ← ← ← ← ここ!!
    },
  }
  const result = await axios.post(env.API_BASE_URL + 'api/v1/images', form, config)
}

経緯

目的

テスト用の大量のデータをフロント経由で準備するのが面倒だったので、API経由でデータを一括登録するためにNode.jsでスクリプトを作ろうとしました。

最初のコード

const fs = require('fs')
const axios = require('axios')
const FormData = require('form-data')

const uploadImage = async ({ auth_token, imageFile }) => {
  const form = new FormData()
  const file = fs.createReadStream(imageFile)
  form.append('image_type')
  form.append('image_file', file)
  const config = {
    headers: {
      'content-type': 'multipart/form-data',
      'X-AUTH-Token': auth_token,
      'X-API-Token': API_TOKEN,
    },
  }
  const result await axios.post(env.API_BASE_URL + 'api/v1/images', form, config)
}

エラー

{
  status: 500,
  statusText: 'Internal Server Error'
}

なるほどわからん

どつぼにはまりました(1時間)

違いの比較

ちゃんと送信できているフロント側のコードと比較するとRequest Headersがなんか違いました

// Node.jsのヘッダー
{
  "Content-Type": "mutlipart/form-data"
}
// フロントが送信しているヘッダー
{
  "Content-Type": "content-type: multipart/form-data; boundary=----WebKitFormBoundaryYtLvDL7BwH9NCRJja"
}

content-type 消してみた

自前で付けている 'content-type': 'multipart/form-data'消してみましたが駄目。
Request が multipart/form-dataになってないことによるエラーが発生。

{
  status: 400,
}
{
  'Content-Type': 'application/x-www-form-urlencoded', 
}

調べたら情報あった

node.js axios FormData でググったらバッチリでました。ありがたや。

https://qiita.com/itoudium/items/d9f04f379d34265387d8#axios%E3%81%A7formdata%E3%82%92%E9%80%81%E3%82%8B

要するに

FormDataが自身の送信用にheader作ってくれるから、それ使えやオラァ!ということです。

結論

同一コードでフロント上では問題なかったので混乱しました
最初からググって調べようね(教訓)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む