Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all 8837 articles
Browse latest View live

Material-ui インストールコマンド

$
0
0

Material-uiのインストールコマンド

下記コマンドを実行

npm install --save @material-ui/icons @material-ui/core @material-ui/system @material-ui/styles

意味

@matesial-ui/core→Material-uiを入手する
@material-ui/icons→公式マテリアルアイコンを使用できる
@material-ui/system→"style functions" と呼ばれる低レベルのユーティリティ関数を提供し、強力な設計システムを構築する
@material-ui/styles→Material-UIコンポーネントを使用していないReactアプリケーションのスタイルを設定する

公式ドキュメントはこちら
https://material-ui.com/ja/


JavaScriptフレームワークのプロジェクト作成コマンドを列挙した

$
0
0

はじめに

JavaScript のフレームワークには npm や Yarn などのパッケージマネージャーを使い簡単に依存関係を解決し、プロジェクトの雛形を作成してくれるコマンドが用意されていることが多いです。
スクラッチでの作成もできますが、コマンドラインツールによって簡単にプロジェクトの自動作成、開発サーバーでの実行ができ便利だと感じたため、有名な JavaScript フレームワークの雛形作成コマンドを備忘録として挙げてみます。

各コマンドの <project-name>の部分が作成されるディレクトリ名、デフォルトのプロジェクト名になります。作成するプロジェクトに応じて適宜置き換えてください。

公式のドキュメントに沿って基本となるコマンドをまとめています。プロジェクト作成時に対話形式で設定可能な項目については記事内で扱いません。項目の説明や、利用できるオプションについては公式のドキュメントを参照のうえ実行をお願いします。

前提条件

  • node.js がインストールされていること(バージョン 8 以降、最新の LTS バージョンを推奨)
  • npm もしくは Yarn が利用可能であること(npm は node.js にデフォルトで搭載)

Vue

npm

npm install-g @vue/cli

vue create <project-name>
cd<project-name>
npm run serve

Yarn

yarn global add @vue/cli

vue create <project-name>
cd<project-name>
npm run serve

http://localhost:8080で開発サーバが立ち上がります。

Vue

Nuxt.js

npm

npm init nuxt-app <project-name>
cd<project-name>
npm run dev (yarn dev)

npx

npx create-nuxt-app <project-name>
cd<project-name>
npm run dev

Yarn

yarn create nuxt-app <project-name>
cd<project-name>
yarn dev

http://localhost:3000で開発サーバーが立ち上がります。

nuxt.js

React

npm

npm init react-app <project-name>
cd<project-name>
npm start

npx

npx create-react-app <project-name>
cd<project-name>
npm start

Yarn

yarn create react-app <project-name>
cd<project-name>
yarn start

npm、npx でインストールする場合は Yarn がインストールされているとデフォルトで Yarn が使用されます。

http://localhost:3000で開発サーバーが立ち上がります。

react

Next.js

npm

npx create-next-app <project-name>
cd<project-name>
npm run dev

Yarn

yarn create next-app <project-name>
cd<project-name>
yarn dev

React と同じく npm、npx でインストールする場合は Yarn がインストールされているとデフォルトで Yarn が使用されます。

http://localhost:3000で開発サーバーが立ち上がります。

next.js

Angular

npm

npm install-g @angular/cli

ng new <project-name>
cd<project-name>
ng serve --open

Yarn

npm install-g @angular/cli

ng config -g cli.packageManager yarn
ng new <project-name>
cd<project-name>
ng serve --open

ng serve --openとすることでデフォルトのブラウザで起動します。
http://localhost:4200で開発サーバーが立ち上がります。

angular.js

Svelte

公式で公開されているテンプレートから新規プロジェクトを作る。

npx

npx degit sveltejs/template <project-name>
cd<project-name>
npm install
npm run dev

http://localhost:5000で開発サーバーが立ち上がります。

svelte

おわりに

有名な JavaScript フレームワークの雛形プロジェクト作成コマンドを公式ドキュメントをもとに列挙してみました。簡単なコマンド 1 つですぐに開発を始める環境が作成できるのはとても便利です。フレームワークがここまで発展し、多くの人に選ばれる理由わかった気がします。

公式ドキュメントを見ながら記事を執筆する中で得た気づきが多くあるため、今後 JavaScript フレームワークについて更に理解を深めていきたいです。

以上、ここまで読んでいただきありがとうございました。

参考ドキュメント

Creating a Project | Vue CLI
インストール - NuxtJS
新しい React アプリを作る - React
facebook/create-react-app: Set up a modern web app by running one command.
Create Next App | Next.js
Angular 日本語ドキュメンテーション - ローカル環境とワークスペースのセットアップ
【2019 年 5 月】yarn で @angular/cli
The easiest way to get started with Svelte
sveltejs / template Template for building basic applications with Svelte

Node.jsでAzure IoT Hubにテレメトリを送信するサンプルコードを動かすメモ

$
0
0

はじめに

デバイスから IoT ハブに利用統計情報を送信してバックエンド アプリケーションで読み取るを参考にサンプルコードを動かしてみます。
Image from Gyazo
接続文字列はAzure CLIを使わずに、コンソールから取得します。

Azure IoTについてはこちらを参照。

準備

  • Node.jsをインストールする(今回はv14.1.0を使用)
  • サンプルコードをダウンロードする
  • 手順を参考に、Iot Hubをデプロイする。(スケールはS1を選択。)

IoTデバイスを登録する

Azure IoT Hubコンソール > サイドバー > IoTデバイス > 新規からデバイスを追加する。

Image from Gyazo

追加できたら、追加したデバイスを選択してプライマリ接続文字列をコピーしておく。

Image from Gyazo

データを送信する

ダウンロードしたサンプルコードから、SimulatedDevice.jsを開き、17行目あたりのconnectionStringに先程コピーしたプライマリ接続文字列を貼り付ける。

コードはこんな感じになる。

varconnectionString='{Your device connection string here}';// ←ここに`プライマリ接続文字列`を貼り付ける。varMqtt=require('azure-iot-device-mqtt').Mqtt;varDeviceClient=require('azure-iot-device').ClientvarMessage=require('azure-iot-device').Message;varclient=DeviceClient.fromConnectionString(connectionString,Mqtt);setInterval(function(){// 送信するデータを生成する。(本当はセンサーで測定した値を入れるがシミュレーションのため乱数を使用)vartemperature=20+(Math.random()*15);varmessage=newMessage(JSON.stringify({temperature:temperature,humidity:60+(Math.random()*20)}));message.properties.add('temperatureAlert',(temperature>30)?'true':'false');console.log('Sending message: '+message.getData());// イベントを送信するclient.sendEvent(message,function(err){if(err){console.error('send error: '+err.toString());}else{console.log('message sent');}});},1000);

以下のコマンドをターミナルで実行する。

$ node SimulatedDevice.js

データが送信されている。

Image from Gyazo

送信したデータを受信する

ダウンロードしたサンプルコードから、ReadDeviceToCloudMessages.jsを開き、38行目あたりのconnectionStringAzure IoT Hubコンソール > サイドバー > 組み込みのエンドポイント > イベントハブ五感エンドポイントの値を貼り付ける。
(26行目あたりにeventHubsCompatibleEndpointなどの変数が用意されていますが、無視します。)

Image from Gyazo

コードはこんな感じになる。

constconnectionString=`Endpoint=**********************;SharedAccessKeyName=*****************;EntityPath=********************`;varprintError=function(err){console.log(err.message);};varprintMessages=function(messages){for(constmessageofmessages){console.log("Telemetry received: ");console.log(JSON.stringify(message.body));console.log("Properties (set by device): ");console.log(JSON.stringify(message.properties));console.log("System properties (set by IoT Hub): ");console.log(JSON.stringify(message.systemProperties));console.log("");}};asyncfunctionmain(){console.log("IoT Hub Quickstarts - Read device to cloud messages.");constclientOptions={// webSocketOptions: {//   webSocket: WebSocket,//   webSocketConstructorOptions: {}// }};constconsumerClient=newEventHubConsumerClient("$Default",connectionString,clientOptions);// イベントハブのストリームからデータを取得するconsumerClient.subscribe({processEvents:printMessages,processError:printError,});}main().catch((error)=>{console.error("Error running sample:",error);});

実行する。

$ node ReadDeviceToCloudMessages.js

受信できた。

Image from Gyazo

まとめ

公式のデバイスから IoT ハブに利用統計情報を送信してバックエンド アプリケーションで読み取るを動かしました。
また、Azure CLIを使わずにコンソールから接続文字列を取得しました。

Azure IoT HubのS1スケールは月に2~3000円ほどかかるので、試し終わったら忘れずに止めておきましょう。

次回は、M5系のデバイスからデータを送信してみます。

Node.jsをWindows10にインストールして詰まったこと

$
0
0

背景

AWSでNode.jsを触ってみようと思い立ち、まずはAWSの開発者ガイドに従って開発環境を構築してみた。

参考にしたURL

https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/nodejs-devenv.html
https://qiita.com/taiponrock/items/9001ae194571feb63a5e

詰まったこと

 Node.js&npmをインストールしたので、動作確認(npm start)するとエラーが出てしまった。

node:internal/modules/cjs/loader:928
  throw err;

Error: Cannot find module 'http-errors'
Require stack:
- hoge\app.js
- hoge\bin\www

エラーの出た環境

 OS:Windows10 Pro(バージョン2004 OSビルド19041.746)
 node.jsインストーラ:node-v15.6.0-x64.msi

調べてみた

どうも、Node.jsのインストールは一発目は失敗することが多い模様。(Windowsだから?)

参考にしたURL

https://github.com/nodejs/help/issues/2644
https://qiita.com/Sakuya_wd/questions/9d2af3b47047aad652fc

確認してみた

同じようなトラブルに見舞われているところでは、node_modulesフォルダを消して再インストールするという解決策が提示されていた。
まず、インストールフォルダを確認したところ、自分の環境ではnode_modulesフォルダが存在していなかった。

やってみた

node_modulesフォルダがもうないんだから、そのまま再インストールをやってみる。

npm install

警告は出るけど、エラーは出てないっぽいから、改めて動作確認をした。

npm start

> node-express@0.0.0 start
> node ./bin/www

GET / 200 1701.982 ms - 170
GET /stylesheets/style.css 200 9.003 ms - 111
GET /favicon.ico 404 33.771 ms - 1132

今度はちゃんとサンプルコードが動いた。
インストーラーからだとモジュール類がちゃんと入らないってことなのかな?

Express Tour #2 Express application generator

$
0
0

素早くExpressアプリケーションのスケルトンを作るために、express-generatorを使いましょう。

検証環境

lubuntu 20.04
node.js 14.15.3

express-generator のインストール

まず下記コマンドでexpress-generatorをグローバルインストールします。

$ npm install -g express-generator

アプリの作成

次にアプリケーション用のディレクトリを作ってそこに移動しましょう。

$ mkdir exg-test
$ cd exg-test

express -h コマンドを打つと各オプションについて確認できます。

$ express -h

実行結果

  Usage: express [options] [dir]

  Options:

        --version        output the version number
    -e, --ejs            add ejs engine support
        --pug            add pug engine support
        --hbs            add handlebars engine support
    -H, --hogan          add hogan.js engine support
    -v, --view <engine>  add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
        --no-view        use static html instead of view engine
    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git            add .gitignore
    -f, --force          force on non-empty directory
    -h, --help           output usage information

デフォルトではviewエンジンとしてJadeがインストールされるのでJadeを使いたくない方はオプションを指定してあげる必要があります。
(cssのデフォルトは普通のcssです。)

例として、viewエンジンにEJS, stylesheetエンジンにsassを指定したい場合は以下のコマンドで作成します。

$ express --view=ejs --css=sass

以下のような構成でアプリが作成されます。

 ./
 ../
 app.js
 bin/
 package.json
 public/
 routes/
 views/

依存関係のインストール

npm install で依存関係のあるライブラリをインストールします。

$ npm install

アプリの起動

以下のコマンドを打つと htttp://localhost:3000/ でアプリが起動します。

$ npm start

参考

https://github.com/expressjs/generator#readme

Azure IoT Hub に Node.js で subscribe

$
0
0
azure_subscribe.js
#! /usr/bin/node
// ---------------------------------------------------------------//  azure_subscribe.js////                  Jan/19/2021//// ---------------------------------------------------------------'use strict'const{EventHubConsumerClient}=require("@azure/event-hubs");consteventHubsCompatibleEndpoint="sb://ihsuprodkwres017dednamespace.servicebus.windows.net/"consteventHubsCompatiblePath="iothub-ehub-iot-aa-344012-58f0095d47"constiotHubSasKey="QThy0z2eiCOzKcv2Ni5DZCnHL8Gtabcdefghd4pj5D4="constconnectionString=`Endpoint=${eventHubsCompatibleEndpoint};EntityPath=${eventHubsCompatiblePath};SharedAccessKeyName=service;SharedAccessKey=${iotHubSasKey}`;varprintError=function(err){console.log(err.message);};varprintMessages=function(messages){for(constmessageofmessages){console.log("Telemetry received: ");console.log(JSON.stringify(message.body));console.log("");/*
    console.log("Properties (set by device): ");
    console.log(JSON.stringify(message.properties));
    console.log("System properties (set by IoT Hub): ");
    console.log(JSON.stringify(message.systemProperties));
    console.log("");
*/}};asyncfunctionmain(){console.log("IoT Hub Quickstarts - Read device to cloud messages.");constclientOptions={};constconsumerClient=newEventHubConsumerClient("$Default",connectionString,clientOptions);consumerClient.subscribe({processEvents:printMessages,processError:printError,});}main().catch((error)=>{console.error("Error running sample:",error);});// ---------------------------------------------------------------

必要な値の取得方法

Event Hub-compatible endpoint

az iot hub show --query properties.eventHubEndpoints.events.endpoint --name{
your IoT Hub name}

Event Hub-compatible name

az iot hub show --query properties.eventHubEndpoints.events.path --name{your
 IoT Hub name}

Primary key for the "service" policy to read messages

az iot hub policy show --name service --query primaryKey --hub-name{your IoT
 Hub name}

実行コマンド

export NODE_PATH=/usr/lib/node_modules
./azure_subscribe.js

参考ページ
Hub からテレメトリを読み取る

[Node.js]docker-compose upで気楽に開発環境構築

$
0
0

前提

  • 筆者はMac環境(試してないがWindowsでも動くと思う)
  • dockerコマンドが使える状態
  • npmコマンドが使える状態
  • nodeコマンドが使える状態
  • Dockerの基本的知識(イメージやコンテナの概念)を有する

対象

  • 環境構築を手っ取り早くしたい人
  • Node.jsをdockerで動かしたい人

環境

bash
$ docker -v
Docker version 20.10.2, build 2291f61

$ npm -v
6.14.5

$ node -v
v13.11.0

$ pwd
~/{project_name}

ファイル構成

project
{project_name}├─ node_modules
 |   └─ ...
 ├─ src
 |   └─ index.js
 └─ docker-compose.yml
 └─ Dockerfile
 └─ package.json
 └─ package-lock.json

node_modulesの中身は割愛

Dockerfileの設定

基本的にはこちらの公式ドキュメント通りにやれば良いが、楽に開発したいたので修正する

{project_name}/Dockerfile
FROM node:12# アプリケーションディレクトリを作成するRUN mkdir-p /usr/src/app
WORKDIR /usr/src/app# Dockerfileが置かれているディレクトリ以下をコピーADD . /usr/src/app# アプリケーションの依存関係をインストールするCOPY package*.json /usr/src/appRUN npm install# 本番用にコードを作成している場合# RUN npm install --only=production# アプリケーションのソースをバンドルするCOPY . /usr/src/app
  • FROM node:1212の部分はこちらを参考に自身の好きなバージョンで!
  • WORKDIR /usr/src/app:dockerコンテナの作業ディレクトリを指定
    (変更する場合はDockerfileと後に紹介するdocker-compose.ymlに書かれた/usr/src/appを全て変更する必要あり)

docker-compose.ymlの設定

{project_name}/docker-compose.yml
version: '3'
services:
  app:
    build: .
    command: bash -c 'node src/index.js'
    image: node_test
    volumes: .:/usr/src/app
    ports: "8080:8080"
    tty: true
  • command: bash -c 'node src/index.js'docker-compose upコマンドでコンテナ起動の際に呼ばれるコマンド
  • image: node_test:image名は任意で変更(分かりやすいプロジェクト名とか)
  • volumes: .:/usr/src/app:ローカルのファイルとdockerコンテナ内のファイルを同期させる
  • ports: "8080:8080":ローカルとコンテナ両方とも8080番ポートを使用
  • tty: truedocker-compose upでコンテナが終了しないようにする

(index.jsの設定)

基本的に自身の環境による
以下はこちらの雛形

'use strict';constexpress=require('express');// ConstantsconstPORT=8080;constHOST='0.0.0.0';// Appconstapp=express();app.get('/',(req,res)=>{res.send('Hello World');});app.listen(PORT,HOST);console.log(`Running on http://${HOST}:${PORT}`);

起動

bash
$ docker-compose up

Have fun !!

※ イメージができてない場合、コンテナ起動までに時間がかかる

参考文献

node.jsやnodebrewなどをインストールし.bash_profileで設定完了→次の日できなくなってたの巻/Mac OS X 10.15

$
0
0

正確には次の日ではなくターミナル落として再度開いたら、でしたが、、
mac OS 10.15での環境構築のお話です。
nodeやnodebrewをインストールし、bash_profileに環境設定pathを通します。

homeの中の「.bash_profile」 ファイルには

export PATH=/usr/local:$PATHexport PATH=$HOME/.nodebrew/current/bin:$PATH

と記述済み。念のためターミナルでも

export PATH=$HOME/.nodebrew/current/bin:$PATH

と実施。

で、ターミナルで
node -v
などを実行してちゃんとバージョンが見れておりました。

ーーーーーーーーー

が、時間を開けてもう一度ターミナルを開き、同じ操作をすると
「zsh: command not found: node」となります。

export PATH=$HOME/.nodebrew/current/bin:$PATH

をターミナルで実行すると動作するため、データは入ってはいるよう。

少しはまりましたが、ターミナルにあるようにシェルが「zsh」というバージョンのため、
.bash_profileに書いたものは無効になってしまいます。
この場合、このファイル名をそのまま.zprofileに名前変更すればうまくいきます!
(またはbashに戻す方法でもよし)

macでは、10.15以降デフォルトでシェルがzhsに変更されております。
理由なんかも合わせてさがすと参考にになりました!
https://www.infoq.com/jp/news/2019/07/macos-ditches-bash-for-zsh/


MQTTによるIoT制御を無料でやってみる

$
0
0

前置き

※途中まで頑張りましたが、断念したため供養記事となります。m..m

背景

IoTの制御としてArduino, Raspberry Piなどを用いて各種センサー情報を収集、又はアクチュエータの制御などを想定する。

MQTTとは

  • ネットワークプロトコルの一種
  • HTTPと比較すると以下が特徴的
  • 一対多, 多対多で情報のやりとりが可能
  • リアルタイムでの通信が可能
  • ヘッダー情報が少なくHTTPの10分の1と軽量 など

詳細はIBMのサイトに記載されています。
MQTT の基本知識

基本的に Subscriber(受け手), Publisher(送り手), Broker(中継点)の3者で構成します。
base.png

Brokerにはtopicと呼ばれるパスを設定し、Sub,Pub共に共通のtopicで送受信を行います。
例: Publish =(topic: hoge)=> Subscribe
topicはhoge/bar, hoge/hoge など"/"を用いて階層化することができます。
topicを分けることで任意のクライアント同士で情報のやり取りを行います。
topic.png

MQTTを利用するにあたってはBrokerを構築する必要があります。
手早く無料で利用するには(制約がありますが)いくつかのサービスが利用できます。

構成図

今回は Beebotteと Heroku を組み合わせた場合を紹介します。

  • Beebotte を利用するメリット
    • 接続台数が無制限
    • メッセージが一日あたり5万件送信できる
    • メッセージを一日あたり5千件保存できる
    • SSL接続が可能
  • デメリット
    • 中継点にアプリケーションが乗せられない
    • topicの管理がやや複雑(channel / resource の形。生成、削除にAPIを叩く必要がある) 接続台数と送信可能件数が魅力的ですが、BrokerにDBを接続したり、メッセージによって特定の処理を行いたい場合は工夫が必要です。

そこでHerokuをSubscriber, PublisherとしてBeebotteに接続することで擬似的に実現します。
BeebotteWithHeroku.png

HerokuはPaaSなのでBrokerとして利用できますが、無料だと5台までしか接続できません。

実装

環境

  • Mac
  • node.js v8.12.0 (npm v6.4.1)
  • git v2.14.3 (Apple Git-98)

環境構築

Brokerとトピックの開設

  1. Beebotteのサイトでアカウント登録
  2. Control Panel > Channels > Create New
  3. Channel Name, Description と Resource Name, Description を入力し Create channel
    • 今回の例: ChannelName: TestCh, ResourceName: Hoge
  4. Channels > Channel Name > Channel Tokenを確認(チャンネル毎に別)
  5. Control Panel > Account Settings > Access Management > API Key, Secret Keyを確認

Beebotteの場合 トピック名は "ChannelName / ResourceName" です

MQTT クライアントの実装

Beebotteからライブラリが提供されている他、MQTT.jsや他の言語のライブラリ1でも可能です。
Tutorialsから実装例が紹介されています
今回はMQTT.jsを用いた例を紹介します

プロジェクトを作成するディレクトリで

npm install mqtt --save

Subscriber

メッセージを受信する
トピックを開設した際に確認したChannel Token と トピック名を書き換えてください

subscriber.js
constmqtt=require('mqtt')constCHANNEL_TOKEN='*********************'constclient=mqtt.connect('mqtt://mqtt.beebotte.com',{username:'token:'+CHANNEL_TOKEN,password:''})constonMessageCallback=(topic,message)=>{console.log(topic+''+message)}client.on('message',onMessageCallback)client.subscribe('TestCh/Hoge')

Publisher

メッセージを発信する
インターバルで定期的に送ってます。

publisher.js
constmqtt=require('mqtt')constCHANNEL_TOKEN='*********************'constclient=mqtt.connect('mqtt://mqtt.beebotte.com',{username:'token:'+CHANNEL_TOKEN,password:''});setInterval(function(){constmessage='Hello, world!'client.publish('TestCh/Hoge',message)},1000);

2つのターミナルで動作確認してみます

node publisher.js
node subscriber.js
#TestCh/Hoge   Hello, world!#TestCh/Hoge   Hello, world!#...

メッセージが表示されていればうまく送信、受信できています。

Heroku 編

志半ばで筆を投げました。すみません。

Node.jsのmodule.exportsの仕組みを理解する

$
0
0

はじめに

こちらは、エンジニアの新たな学びキャンペーンに向けた記事となります。

Node.js + Express で作る Webアプリケーション 実践講座を参考にしながら、
module.exportsについて理解を深めたことを記事にします。

実行環境

  • Node.js v12.16.3
  • Express 4.16.1
  • 10.4.11-MariaDB

本記事の概要

私は今現在、Webアプリケーションの開発をしていますが、ある問題を抱えています。
その問題とは、1つのファイル内のソースコードが膨らみすぎて可読性が落ちているというものです。
これはデータベースへの接続、ミドルウェアの呼び出し、レスポンスの処理内容など、あらゆる情報をapp.js内に書き込んでいることに由来します。

そこで、app.js内のソースコードを削減することを目的に、
データベース接続を行う関数を別ファイルdbConnect.jsに記述し、
module.exportsを使ってそれをapp.jsから呼び出すようにリファクタリングしました。

本記事では、はじめにmodule.exportsについて例題を用いて解説し、
その後で応用として、データベース接続用の関数をmodule.exportsを使って呼び出します。

対象のUdemy講座で学んだこと

対象の講座で学んだことのうち、特に本記事へと反映する内容は以下となります。

  • module.exportの使い方
  • requireの使い方

module.exportsとは

JavaScript(Node.js)において、
あるファイルに存在する変数や関数を、別のファイルで実行する機能です。

似たようなものにexportsがありますが、本記事では触れません。

(例) sub.js内の関数をmain.jsで実行する

sub.jsで宣言した変数をmain.jsで実行します。

(*varletではなくconstで宣言しているので、厳密には変数ではなく定数です。)

main.js
constfoo=require("./sub.js");// sub.jsからmodule.exportsで指定した変数を読み込み、変数fooに代入するfoo("bee");// bee
sub.js
consthoge=function(bar){console.log(bar);}module.exports=hoge;// main.jsからrequireされたら、hogeという変数を渡す

(実践) データベース接続用の関数を、別ファイルに配置する

app.jsにすべてのソースコードを書き込んでいた状態から、
app.jsdbConnect.jsの2つにソースコードを分割します。

リファクタリング前のソースコード

app.js
constexpress=require("express");constapp=express();constmysql=require("mysql");constdbcn=mysql.createConnection({host:"localhost",user:"root",password:"1234",database:"idea"})app.set("view engine","ejs");app.get("/",(req,res)=>{constsql="select * from ideatext";dbcn.query(sql,function(err,result,field){if(err)throwerr;console.log(result);res.render("index",{idea:result});})})app.listen(3000);

リファクタリング後のソースコード

app.js
constexpress=require("express");constapp=express();constmysql=require("mysql");constdbcn=require("./dbConnect.js")constconnection=dbcn.dbcn;app.set("view engine","ejs");app.get("/",(req,res)=>{constsql="select * from ideatext";dbcn.query(sql,function(err,result,field){if(err)throwerr;console.log(result);res.render("index",{idea:result});})})app.listen(3000);
dbConnect.js
constmysql=require("mysql");constdbcn=mysql.createConnection({host:"localhost",user:"root",password:"1234",database:"idea"})module.exports=dbcn;

参考

Node.js + Express で作る Webアプリケーション 実践講座

2021年、gulp-sassをインストールしようとして躓いた

$
0
0

この度完全新規のコーディング案件に携わることになったため、久しぶりに1年前まで使用していたpackage.jsonを引っ張りだしnpm intallを実行したところ、gulp-sassのインストールでエラーを吐いてしまい躓きました。
3時間調査したり悩んだりした結果、解決しましたので備忘録として残します。

エラー状況

Windows10環境で npm install gulp-sass --save-devすると、下記の通りログが出力され、インストールできない。
私のPCにはNode.jsの【最新版(v15.5.0)】がインストールされておりました。

エラーのログ

cmd
PS G:\data\html> npm install gulp-sass --save-dev
npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.

> node-sass@4.14.1 install G:\data\html\node_modules\gulp-sass\node_modules\node-sass
> node scripts/install.js

Downloading binary from https://github.com/sass/node-sass/releases/download/v4.14.1/win32-x64-88_binding.node
Cannot download "https://github.com/sass/node-sass/releases/download/v4.14.1/win32-x64-88_binding.node": 

HTTP error 404 Not Found

Hint: If github.com is not accessible in your location
      try setting a proxy via HTTP_PROXY, e.g.

      export HTTP_PROXY=http://example.com:1234

or configure npm proxy via

      npm config set proxy http://example.com:8080

> node-sass@4.14.1 postinstall G:\data\html\node_modules\gulp-sass\node_modules\node-sass 
> node scripts/build.js

Building: C:\Program Files\nodejs\node.exe G:\data\html\node_modules\node-gyp\bin\node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library=
gyp info it worked if it ends with ok
gyp verb cli [
gyp verb cli   'C:\\Program Files\\nodejs\\node.exe',
gyp verb cli   'G:\\data\\html\\node_modules\\node-gyp\\bin\\node-gyp.js',
gyp verb cli   'rebuild',
gyp verb cli   '--verbose',
gyp verb cli   '--libsass_ext=',
gyp verb cli   '--libsass_cflags=',
gyp verb cli   '--libsass_ldflags=',
gyp verb cli   '--libsass_library='
gyp verb cli ]
gyp info using node-gyp@3.8.0
gyp info using node@15.5.0 | win32 | x64
gyp verb command rebuild []
gyp verb command clean []
gyp verb clean removing "build" directory
gyp verb command configure []
gyp verb check python checking for Python executable "python2" in the PATH
gyp verb `which` failed Error: not found: python2
gyp verb `which` failed     at getNotFoundError (G:\data\html\node_modules\which\which.js:13:12)
gyp verb `which` failed     at F (G:\data\html\node_modules\which\which.js:68:19)
gyp verb `which` failed     at E (G:\data\html\node_modules\which\which.js:80:29)
gyp verb `which` failed     at G:\data\html\node_modules\which\which.js:89:16
gyp verb `which` failed     at G:\data\html\node_modules\isexe\index.js:42:5
gyp verb `which` failed     at G:\data\html\node_modules\isexe\windows.js:36:5
gyp verb `which` failed     at FSReqCallback.oncomplete (node:fs:199:21)
gyp verb `which` failed  python2 Error: not found: python2
gyp verb `which` failed     at getNotFoundError (G:\data\html\node_modules\which\which.js:13:12)
gyp verb `which` failed     at F (G:\data\html\node_modules\which\which.js:68:19)
gyp verb `which` failed     at E (G:\data\html\node_modules\which\which.js:80:29)
gyp verb `which` failed     at G:\data\html\node_modules\which\which.js:89:16
gyp verb `which` failed     at G:\data\html\node_modules\isexe\index.js:42:5
gyp verb `which` failed     at G:\data\html\node_modules\isexe\windows.js:36:5
gyp verb `which` failed     at FSReqCallback.oncomplete (node:fs:199:21) {
gyp verb `which` failed   code: 'ENOENT'
gyp verb `which` failed }
gyp verb check python checking for Python executable "python" in the PATH
gyp verb `which` succeeded python C:\Documents and Settings\●●●\AppData\Local\Programs\Python\Python39\python.EXE
gyp ERR! configure error 
gyp ERR! stack Error: Command failed: C:\Documents and Settings\●●●\AppData\Local\Programs\Python\Python39\python.EXE -c import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack   File "<string>", line 1
gyp ERR! stack     import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack                       ^
gyp ERR! stack SyntaxError: invalid syntax
gyp ERR! stack
gyp ERR! stack     at ChildProcess.exithandler (node:child_process:333:12)
gyp ERR! stack     at ChildProcess.emit (node:events:376:20)
gyp ERR! stack     at maybeClose (node:internal/child_process:1063:16)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:295:5)
gyp ERR! System Windows_NT 10.0.19042
gyp ERR! command "C:\\Program Files\\nodejs\\node.exe" "G:\\data\\html\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library="
gyp ERR! cwd G:\data\html\node_modules\gulp-sass\node_modules\node-sass
gyp ERR! node -v v15.5.0
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok
Build failed with error code: 1
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN GulpTask@1.0.0 No description
npm WARN GulpTask@1.0.0 No repository field.
npm ERR! node-sass@4.14.1 postinstall: `node scripts/build.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the node-sass@4.14.1 postinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Documents and Settings\●●●\AppData\Roaming\npm-cache\_logs\2021-01-20T16_23_09_981Z-debug.log 

debug.logを確認すると同じエラーが出力されておりました。
Pythonが必要そうなログが出ているのでインストールしたり、npmのキャッシュを消して再インストールし直したり…
検索して出てきたものを片っ端から試しましたが直りません。
なんとなく、「どうもnode-sassが悪いっぽい」ということだけ情報を掴みました。

解決策

Node.jsのバージョンを【推奨版】にダウングレードしました。
(Node.jsをアンインストール → 公式サイトから左側の「推奨版」をダウンロード&インストール)
node.png

これだけで無事gulp-sassをインストールすることができました。

原因

なぜダウングレードするだけで解決したのか?
原因はgulp-sass内で使用しているnode-sassにありました。

  • node-sassの最新バージョンはv5.0.0(これはNode.js v15.x に対応しています)
  • gulp-sass(v3.2.1)で使用しているnode-sassはv4.14.1。これはNode.js v14.x までしか対応していません

node-sassがどのNode.jsのバージョンに対応しているか?はGithubのReleaseを開くと確認できます。
https://github.com/sass/node-sass/releases
nodesass.png

バージョンに注意!

今まで「最新こそ正義」と思い最新版を入れてきましたが、こんな落とし穴があるとは思いませんでした。
どのソフトなどを使用していてもそうですが、自分が使うパッケージに合わせてインストールするバージョンを選ぶか、使うパッケージが最新版に追いついていないのであれば代替のものを探すことが大事ですね。

Azure IoT Hub の イベントハブ互換エンドポイントに Node.js で subscribe

$
0
0

次のプログラムを改造して、イベントハブ互換エンドポイントを使うようにしました。
Azure IoT Hub に Node.js で subscribe
Hub に subscribe しているので、その Hub 内の Device に届いた総てのメッセージが表示されます。Device の認証が、SAS トークンでも、CA 証明書でも、どちらも表示されます。

azure_endpoint_subscribe.js
#! /usr/bin/node
// ---------------------------------------------------------------//  azure_endpoint_subscribe.js////                  Jan/21/2021//// ---------------------------------------------------------------'use strict'constdotenv=require('dotenv')const{EventHubConsumerClient}=require("@azure/event-hubs");dotenv.config()constendpoint_connectionString=`${process.env.ENDPOINT}`varprintError=function(err){console.log(err.message)};varprintMessages=function(messages){for(constmessageofmessages){console.log("Telemetry received: ")console.log(JSON.stringify(message.body))console.log("")/*
    console.log("Properties (set by device): ");
    console.log(JSON.stringify(message.properties));
    console.log("System properties (set by IoT Hub): ");
    console.log(JSON.stringify(message.systemProperties));
    console.log("");
*/}}// ---------------------------------------------------------------asyncfunctionmain(){console.error("*** azure_endpoint_subscribe.js *** start ***")constclientOptions={}constconsumerClient=newEventHubConsumerClient("$Default",endpoint_connectionString,clientOptions)consumerClient.subscribe({processEvents:printMessages,processError:printError,})}main().catch((error)=>{console.error("Error running sample:",error)})// ---------------------------------------------------------------
.env
ENDPOINT="Endpoint=sb://ihsuprodkwres017dednamespace.servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=vL1ze1abcdefgh48cMK7l6nv6+o37k2s9F70SD+LLZUs=;EntityPath=iothub-ehub-iot-bb-344012-58f0012d36"

Azure Portal で エンドポイントの値を取得

endpoint_jan21.png

sam local start-apiでヘッダーが勝手にキャメルケースになるんだが?

$
0
0

表題の通り、sam local start-apiでヘッダーが勝手にキャメルケースになる問題についてです。

こちらにドンピシャの回答があるのですが、内部で使っているFlaskの仕様だそうです。
Headers are received in Camel-Case · Issue #1860 · aws/aws-sam-cli

仕方ないのでNode.jsでは下記ワークアラウンドをしてヘッダーをすべて小文字にして対応しましょう。
(Pythonならissueのコメントにサンプルコードが載っています)

consttoLowerCaseKey=function(object){letnewObject={};for(letkeyinobject){if(object.hasOwnProperty(key)){newObject[key.toLocaleLowerCase()]=object[key];}}returnnewObject}

Slackの今日のチャンネル内容をLINEに送信する(Google Cloud Functions)

$
0
0

表題の内容を試す機会があったので、作業内容とサンプルコードを紹介したい思います。

環境

  • Slack: フリープランでOK
  • LINE
  • GCP Coud Functions
  • 実行環境はNode.js

*各サービスのドキュメントはすでにネットに豊富にあるので、今回は細かい設定方法の解説を省きます

サービス設定

Slack

slack api 設定

https://api.slack.com/apps
Create New Appから新規appを作成。その後以下を設定。

  • Features -> OAuth & Permissions でBot Token Scopesに以下の権限を付与
    channels:history
    chat:write
    commands
    groups:history
    im:history
    mpim:history
    users:read

  • Features -> OAuth & Permissions -> OAuth Tokens & Redirect URLs -> Install to Workspaceボタンをクリック
    Bot User OAuth Access Token [xoxb-**...] を取得。後ほど利用する

  • Settings -> Basic Information -> Signing Secretをshowで一時的に表示してメモ。後ほど利用する

情報を取得したいチャンネルのidを取得する

こちらの記事が参考になると思います。

対象チャンネルに上記で作成したappを追加

slackの チャンネル詳細->その他 にあります
image.png

LINE

LINE Notifyを使用します。トークンを発行し、送信先トークルームにLINE notifyを招待します。
こちらの記事が参考になると思います。

Cloud Functions実装

デプロイの手法は複数あると思いますが、webインターフェースを用いた手法だとこちらが参考になると思います。

コードはこちらのリポジトリに置きました。
https://github.com/hisa-shimoji/SlackTodayCh2Line

今回のデプロイの際は

  • トリガーのタイプ: http
  • 認証: "認証が必要"

を選択します。ランタイム環境変数に以下の値を設定します。

変数名解説
SLK_BOT_TOKENslack設定時に確認した Bot User OAuth Access Token [xoxb-**...] の値
SLK_BOT_SIGN_SECRETslack設定時に確認したSigning Secretの値
SLK_BOT_MONITOR_CHANNELslack設定時に確認した対象チャンネルのid
L_NOTIFY_KEYLINE notifyのトークン
L_MSG_PREFIXLINEメッセージの前に付加する文字列 改行は\nで設定 必要なければ空白に
L_MSG_SUFFIXLINEメッセージの後に付加する文字列 改行は\nで設定 必要なければ空白に

実行テスト

デプロイ後、webインターフェースから関数をテストするでテストできます。
image.png

成功すると該当slackチャンネルの当日分のメッセージ(発言者と内容)がLINEへ送信されます
image.png

定期実行

GCP Cloud Schedulerを用いて定期実行が可能です。 こちらの記事が参考になると思います。

参考情報

https://cloud.google.com/functions/docs/quickstart-nodejs?hl=ja
https://qiita.com/YumaInaura/items/0c4f4adb33eb21032c08
https://qiita.com/iitenkida7/items/576a8226ba6584864d95
https://qiita.com/nirasan/items/0d9aad7da324ecd789f4

corrs について 猿でもわかる

$
0
0

バックエンド側でnode,expressを触っている人向け

CORRS とは、API通信で値(param)など、バックエンド側のデータを表示させるために
バックエンド側で設定するための物です。

なので、今回は設定方法だけ記載します。

これを書いておけばHTTP通信は正常に行われます。

バックエンド側に
app.use((req, res, next) => {
// res.header("Access-Control-Allow-Origin", "http://localhost:4200");
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, Authorization, Accept, Content-Type");
// res.header("Access-Control-Allow-Headers", "*");
res.header('Access-Control-Allow-Credentials', "true");

// OPTIONSリクエスト(プリフライトリクエスト)への応答
// 参考: https://developer.mozilla.org/ja/docs/Web/HTTP/CORS#preflighted_requests
if (req.method == "OPTIONS") {
    res.send(200);
} else {
    next();
}

});

今回はAngularを使っている方向けです。

指摘がありましたら、コメント等お願いします。


node.jsで集計処理をしてみた。

$
0
0

初めに

node.js の学習のために集計をしてみました。
実際のコードです。
https://github.com/shohei-lob/adding-up.git 

環境はLinuxです。

今回すること

「2010 年から 2015 年にかけて 15〜19 歳の人が増えた割合の都道府県ランキング」作成。
地域経済分析システム(RESAS:リーサス)で提供されている2010 年と 2015 年の都道府県別 10 代の人口データを集計していきます。データはCSV方式のものです。

要件定義


1.ファイルからデータを読み取る
2.2010 年と 2015 年のデータを選ぶ
3.都道府県ごとの変化率を計算する
4.変化率ごとに並べる

ファイルからデータを読み取る

app.js
'use strict';//ファイルを読み込むconstfs=require('fs');constreadline=require('readline');constrs=fs.createReadStream('.hoge.csv');constrl=readline.createInterface({input:rs,output:{}});rl.on('line',lineString=>{console.log(lineString);});

以下部分が理解するのに苦しみました

rl.on('line', lineString => {
  console.log(lineString);
}); 

部分が理解するのに苦しみました。公式ドキュメントにもあるようにlineが呼ばれるたびに第二引数"lineString"が呼ばれる。

2010 年と 2015 年のデータを選ぶ

app.js
rl.on('line',lineString=>{constcolumns=lineString.split(',');constyear=parseInt(columns[0]);constprefecture=columns[1];constpopu=parseInt(columns[3]);if(year===2010||year===2015){console.log(year);console.log(prefecture);console.log(popu);}});

1行ずつ理解していきます。

lineStringで与えられた文字列をカンマで分割しcolumnsに代入。

const columns = lineString.split(',');

集計年(0 番目),都道府県(1 番目),15〜19 歳の人口(3 番目)をそれぞれ変数に保存しています。
parseInt()は、年と人口を整数値にしています。

 const year = parseInt(columns[0]);
  const prefecture = columns[1];
  const popu = parseInt(columns[3]);

もし年が、2010または2015の場合出力。

  if (year === 2010 || year === 2015) {
    console.log(year);
    console.log(prefecture);
    console.log(popu);
  }

都道府県ごとの変化率を計算する

集計データは以下3つになる。
・2010 年の人口の合計
・2015 年の人口の合計
・計算された 2015 年の 2010 年に対する変化率
連想配列とオブジェクトの2つのデータ型を使い集計データを表す。

今回はmapを使います。

app.js
'use strict';constfs=require('fs');constreadline=require('readline');constrs=fs.createReadStream('.hoge.csv');constrl=readline.createInterface({input:rs,output:{}});constprefectureDataMap=newMap();// key: 都道府県 value: 集計データのオブジェクトrl.on('line',lineString=>{constcolumns=lineString.split(',');constyear=parseInt(columns[0]);constprefecture=columns[1];constpopu=parseInt(columns[3]);if(year===2010||year===2015){letvalue=prefectureDataMap.get(prefecture);if(!value){value={popu10:0,popu15:0,change:null};}if(year===2010){value.popu10=popu;}if(year===2015){value.popu15=popu;}prefectureDataMap.set(prefecture,value);}});rl.on('close',()=>{console.log(prefectureDataMap);});

以下集計されたデータを格納する連想配列です。

const prefectureDataMap = new Map(); // key: 都道府県 value: 集計データのオブジェクト

以下コードは連想配列 prefectureDataMap からデータを取得しています。
value の値が Falsy の場合に、value に初期値となるオブジェクトを代入します。
changeが null の理由は変化率が0の可能性があるからです。

let value = prefectureDataMap.get(prefecture); //都道府県のデータをとる
if (!value) { // データが取れてない時
  value = {
    popu10: 0, // 2010年の人口
    popu15: 0, // 2015年の人口
    change: null //変化率
  };
}

全ての行を読み終えた時'close'を呼び出す。

rl.on('close', () => {
  console.log(prefectureDataMap);
}

まとめ

APIの使い方を理解していきたいです。
データの型をきっちりしないとエラーが起きる。

【Typescript】 Error: Cannot find module 'express' の解決

$
0
0

あるファイルを読み込もうとしたら、エラーメッセージが出た。

nodeindex.jsinternal/modules/cjs/loader.js:638throwerr;^Error:Cannotfindmodule'express'atFunction.Module._resolveFilename(internal/modules/cjs/loader.js:636:15)atFunction.Module._load(internal/modules/cjs/loader.js:562:25)atModule.require(internal/modules/cjs/loader.js:692:17)atrequire(internal/modules/cjs/helpers.js:25:18)atObject.<anonymous>(/home/ec2-user/environment/photo/realitycapture/reality.capture-nodejs-photo.to.3d/index.js:18:15)atModule._compile(internal/modules/cjs/loader.js:778:30)atObject.Module._extensions..js(internal/modules/cjs/loader.js:789:10)atModule.load(internal/modules/cjs/loader.js:653:32)attryModuleLoad(internal/modules/cjs/loader.js:593:12)atFunction.Module._load(internal/modules/cjs/loader.js:585:3)

解決策

npm insatll express

expressを入れましょう。以上。

Githubプロフィールに貼れる画像を動的に生成して返すエンドポイントを作る

$
0
0

巷ではGithubのプロフィールをデコるのが流行っています。
具体的にはGitHub Readme Stats を利用してGitHubプロフィールをカッコよくするのような記事を読んでもらえばいいんですが、ここで紹介されている物以外を載せたい場合があると思います。

そこで、今回は試しにTwitterのプロフィール情報を取得し画像にして返すtwitter-profile-cardというものを書きました。
Vercelにデプロイされており、URLにidのクエリを付けて叩くとTwitterのプロフィールの画像が返ってきます。
Twitterの情報を取得する手順で他のデータを取得すれば応用が利くはずです。

記事では書いたCSSの詳細は省いていますが、この様な感じで表示されます。(画像はpngにした物ですが、リンク先は生成された物になっています。)
詳しくはリポジトリを見て下さい。

twitter-profile-card-default

やりたいこと

  1. Twitter APIを叩いて、プロフィールを取得
  2. HTMLElementにデータを埋め込んでスタイリング1
  3. PuppeteerでHTMLElementのスクリーンショットを撮る
  4. svgの配下のimageタグにスクリーンショットを埋め込んだレスポンスを返す
  5. これらをデプロイ

構成

.
├── README.md
├── package.json
├── vercel.json
├── api
│   └── index.ts
├── src
│   ├── createCard.ts
│   ├── createElement.tsx
│   └── getTwitterData.ts
└── tsconfig.json
  • /apiがエンドポイントになります

データの取得

好きなように取得してください。
今回はTwitterのプロフィール情報を取得し返す、と言う事で適当に取得します。

src/getTwitterData.ts
exportfunctiongetTwitterData({id})=>{constheaders={Authorization:`Bearer ${process.env.TWITTER_BEARER_TOKEN}`}constparams={screen_name:id}constuserShowEndoPoint='https://api.twitter.com/1.1/users/show.json'returnnewPromise((resolve,reject)=>{axios.get(userShowEndoPoint,{headers,params}).then((response)=>resolve(response.data)).catch(async(err)=>{returnreject(err.response)})})}

データをスタイリングし、Puppeteerでスクリーンショットを撮る

VercelAWS Lambda上で動いてる為、デプロイパッケージのサイズに制限があります。
Puppeteerに同梱さているChrome単体パッケージが単体で250MBもあるので、そのままVercelにデプロイしてしまうと、サイズ上限に引っかかってしまいます。

そこで、サイズ上限を回避するためにchrome-aws-lambdapuppeteer-coreを利用します。2
この2つはバージョンを合わせる必要があるので注意が必要です。

src/createCard.ts
importchromefrom'chrome-aws-lambda'importpuppeteerfrom'puppeteer-core'

また、ローカル環境ではchrome-aws-lambdaが働いてくれないので、サーバー上で動いているかを条件分けし、ローカルでは自分のPCに入っているChromeを使うようにします。

src/createCard.ts
constbrowser=awaitpuppeteer.launch(process.env.AWS_REGION?{args:chrome.args,executablePath:awaitchrome.executablePath,headless:chrome.headless}:{args:[],executablePath:process.platform==='win32'?'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe':process.platform==='linux'?'/usr/bin/google-chrome':'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'})

データを表示する為に、htmlを書きます。
スタイリングにインテリセンスが効かないと辛いので、.tsx | .jsx拡張子のファイルを作り、JSX.Elementを返す関数を書きます。
全てを書くと長いので、ここではヘッダーを表示する部分だけ書きます。

src/createElement.tsx
import*asReactfrom'react'exportfunctioncreateElement(tweetData){constheader={height:'33%',width:'100%',overflow:'hidden'}constheaderImage={height:'100%',width:'100%',objectFit:'cover'}return(<divstyle={header}><imgsrc={tweetData.profile_banner_url}alt="header image"height="100px"width="300px"style={headerImage}/></div>)}

この様にinline-styleでスタイリングしていきます。

このJSX.Elementreact-dom/serverrenderToStringを使う事でstring型に変換でき、それをPuppeteerで読み込み、スクリーンショットを撮ります。

src/createCard.ts
import{renderToString}from'react-dom/server'import{createElement}from'./createElement'
src/createCard.ts
constelement=createElement(tweetData)constpage=awaitbrowser.newPage()awaitpage.setContent(`<html>
      <head>
        <style>
          body {
            width: "${width}";
            height: "${height}";
          }
        </style>
      </head>
      <body>${renderToString(element)}</body>
    </html>
  `)constimage=awaitpage.$('body')constbuffer=awaitimage.screenshot({encoding:'base64'})

補足

日本語が混じったDOMをそのままスクリーンショットしてしまうと、日本語のフォントがPuppeteerに存在しないので文字化けしてしまいます。
ですのでgooglefontsなどのcdnからfontを読み込む様にします。

src/createCard.ts
awaitchrome.font('https://rawcdn.githack.com/googlefonts/noto-cjk/be6c059ac1587e556e2412b27f5155c8eb3ddbe6/NotoSansCJKjp-Regular.otf')awaitchrome.font('https://rawcdn.githack.com/googlefonts/noto-fonts/ea9154f9a0947972baa772bc6744f1ec50007575/hinted/NotoSans/NotoSans-Regular.ttf')

撮ったスクリーンショットをクライアントに返す

上述しましたが、クライアント側のエンドポイントは/apiになります。
(いくつかのレポジトリでこうなってたので参考にしました。)
./api/index.tsで、リクエストを受けレスポンスを返す処理を行います。

exportdefaultasync(req,res)=>{const{id}=req.queryres.send(id)}

req.queryに叩いたURLのqueryが入ります。
(例えば/api?id=Twitterとすると、req.query.idにTwitterが入ります。)
res.sendでクライアントにレシポンスを返すことができ、res.setHeaderでHeaderを設定します。

先ほど撮ったスクリーンショットをsvgに埋め込み、クライアントに返します。

src/createCard.ts
return`<svg
    xmlns="http://www.w3.org/2000/svg"
    width="${width}"
    height="${height}"
    viewport="0 0 ${width}${height}"
    fill="none"
  >
    <image href="data:image/jpeg;base64,${buffer}" x="0" y="0" width="100%" height="100%"/>
  </svg>
`
api/index.ts
import{createCard}from'../src/createCard'import{getTwitterData}from'../src/getTwitterData'exportdefaultasync(req,res)=>{constresult=awaitgetTwitterData(req.query)// Twitterのデータ取得constsvgImage=awaitcreateCard()// svg画像のHTMLelementを取得res.setHeader('Content-Type','image/svg+xml')// svgを指定res.setHeader('Cache-Control',`public, max-age=${60*60*12}`)// データの変化があまりないのでキャッシュを12時間にres.send(svgImage)// データを返す}

これでクライアントにsvg画像を返すことができました。

確認、デプロイ

vercel.jsonを設定し、Vercel devでローカルサーバーを起動できます。
http://localhost:3000/api?id=Twitterで画像が表示されれば完成です。

あとはvercelコマンドでデプロイできます、簡単ですね。

まとめ

参考


  1. スタイリングにインテリセンスが効かないと辛いので(1敗)、スタイリングはjsxで書いていき、ReactDOMServer.renderToString()を使って変換します 

  2. chrome-aws-lambdaの配下にPuppeteerが存在し、それを利用すれば一見動きそう何ですが、puppeteer-coreが依存関係にあり、両方必要です 

初めてのクラウド、初めての Azure -簡単なサーバーアプリをオンプレから移行-

$
0
0

初めに

*以下の記事を Qiita へ移植したものです。普段使用する技術情報プラットフォームが Qiita な方もいるかもということで。
(あとは単純に反応の違いとかあるのかという興味本位で)

https://zenn.dev/minominominoru/articles/fc40d09d89d24f

概要

皆さん、クラウド使ってますか?実際のところ使ったことはないという方も多いんじゃないかなと思ってたりします。そして使ってみたい、学んでみたいけど最初の一歩や学び方が分からない方も多いかなと思います。

やっぱり技術は実際に触ってみた方がイメージ掴みやすいし、学びやすいと(個人的に)思います。
なので、手元の PC でプログラムを実行した後に、クラウドに移行してみるまでの簡単なハンズオンを用意してみました。

なお、ちょっとしたツールのダウンロードや、アカウントの作成等は必要ですが、プログラミングの経験がない方でもできる限り簡単にできるように心がけて書いてみました。(指定したコマンドを入力するだけで試せますし、そんなに打つこともないです。)

所要時間はアカウントの作成や一部のツールのインストールを除けば 1 時間もあればできるんじゃないかなと思ってます。もちろん、無料で試せます。(アカウント作成でクレカは必要だったかと思いますが)

あくまでもちょっと体験してみるくらいにはなりますが、少し Web の知識の話とかも概要だけですが入れていたりするので、クラウドにこれから触るって方の最初の一歩の助けにでもなれたら良いなって思います。

対象の人

本記事は、以下の感じの方がメインのターゲットかなと思ってます。
- 「クラウドってよく聞くけど、実際のところ何が良いの?」って方
- 「クラウドや Azure 使ったことないけどちょっと試してみたい」って方
- プログラミングの経験はあまりないが体験してみたいって方
- 何でもよいからクラウドを体験してみたいって方

なので、例えば Azure や AWS 等に慣れている方からしたらあまり学びはないかもです。

ただ、上記の方々以外にも、node.js を使ったことがない方なんかにも、もしかしたら楽しんでいただけるのではないかなと思います。(欲を言うとちょっとでも気になったら読んでみて欲しいとは思ってます)

簡単な用語の説明

本当にごく一部、最小限知っててもらえたらという感じです。
厳密な定義というよりは、やんわりとイメージを持ってもらえたらくらいの解説にしてます。

一般的な web の用語

  • URL
    ザックリというとネットワーク上のリソースの場所です。例えば、https://www.google.com/という URL を開くとよく見る Google の検索画面が表示されます。

  • HTTP リクエスト
    あるリソース(NW 上のサーバー等)に対して処理等を要求する。例えば、 Browserで URL へアクセスして Web ページを開くのはGETです。色んな種類の HTTP リクエストがありますが、ここでは GET と POST という2種類だけ出てきます。

  • エンドポイント
    リクエストを送る際に「そのサーバーのどの機能を使う?」って指定をするイメージです。例えば、www.hogehoge.com/pagea にアクセスしたら pageA,www.hogehoge.com/pagebにアクセスしたら pageb が出力されるみたいに、一つのサーバーに複数のエンドポイントを用意できます。

  • ローカル(ホスト)
    自分の PC 上でサーバーアプリを起動する際等に「ローカルで起動する」といった表現をします。

  • オンプレミス
    クラウドではなく、自分/自社のネットワーク環境のことだと思っていただけたらと。インターネットとかを経由しないのでクローズドなネットワークとかローカルネットワークとか言うこともあるかもです。(厳密な定義の差等はあるかもですが割愛)

Azure の用語

  • Azure
    そもそもですが、クラウドサービスの一つです。

  • App Service
    Azure のサービスの一種で Web アプリの作成等で使用します。
    https://azure.microsoft.com/ja-jp/services/app-service/

  • リソース
    あるサービスの自分が使用する個体です。例えば、上記の App Service を使って複数の Web サイトを作成する際には App Service のリソースを複数作成します。

  • リソースグループ
    上記のリソースを管理するために使用します。色んなサービスの色んなリソースを作成することになるので、うまく管理するのに使います。

  • Deploy
    ザックリというと自分の作成したアプリ等をクラウド上に配置することです。

準備

*私は windows 10 で実行しています。

前提条件

  • サーバーアプリ実行用の PC : スペックとかはそんなに必要ないです。
  • スマホ : 同上。ブラウザ(CHrome,Safari,Edge 等) を開けさえすれば大丈夫。
  • Wi-Fi 環境 : 上記の端末を同じネットワーク(Wi-Fi 環境)に繋げます。

準備作業

上記前提条件の上で。

  • Azure アカウント
    以下から Azure アカウントを作成します。クレカが必要だったかなと思います。
    https://azure.microsoft.com/ja-jp/free/

  • node.js
    ザックリいうと JavaScript という言語でサーバーアプリを作成する際によく使用します。
    Long Term Support(LTS) の方で自分の PC にあったものを入れてください。
    https://nodejs.org/ja/download/

  • VSCode
    コードの編集等で使用します。Azure との連携がよかったり、拡張機能で様々な機能が追加できます。
    https://code.visualstudio.com/Download

また、以下の拡張機能も追加してください。

  • Azure 拡張機能

Azure へのデプロイなどで使用します。各サービスごとに機能が出ていたりしますが、最低でも App Service の機能を入れてもらえたら大丈夫です。
https://marketplace.visualstudio.com/items?itemName=ms-vscode.vscode-node-azure-pack

  • REST Client

サーバーアプリの機能を試すのに便利な拡張機能です。個人的には普段からよく使ってます。
https://marketplace.visualstudio.com/items?itemName=humao.rest-client

オンプレでサーバーを実行

さて、前準備が終わったらまずはオンプレでサーバーアプリを実行してみましょう。
ちなみに、早くクラウドに触りたいって方は一応サンプルコードだけ下から落として、クラウドのところまで飛んでもらうのもありです。(ただ、node.js や Cloud が初めての方は頑張って書いたのでぜひ読んで欲しいです)

以下の Github にサンプルコードを用意しました。
https://github.com/MinoMinoMinoru/simple-restify-server/tree/master

git で clone する方法もありますが、そういった方法に慣れない方は zip でダウンロードすることもできます。

image.png

とりあえず、プロジェクトファイル一式がある場所で Powershell(適宜好みのコマンド ツール)を開きましょう。Windows の方は、以下の画像のようにエクスプローラーから開くこともできます。

image.png

image.png

serverアプリの実行

以下のコマンドで必要な module を install します。(package.json にそういう感じのことを書いてます。気になる方は npm というパッケージ管理ツールについて調べてみてください。)

npm install

続けて以下のコマンドでサーバープログラムを実行します。

npm start

まずはブラウザで以下の URL にアクセスしてみましょう。

http://localhost:3978

以下のように私が雑に作ったページが出力されます。

image.png

次に、以下の URL にアクセスしてみましょう。

http://localhost:3978/test-get


image.png

なんか違うページが表示されているかと思います。
では、ちょっとだけ実行されているコードを見てみましょう。

constrestify=require('restify');constfs=require('fs');// Create HTTP serverconstserver=restify.createServer();server.listen(process.env.port||process.env.PORT||3978,()=>{console.log("Please open the following URLs in Browser")console.log("[URL A]");console.log("http://localhost:3978")console.log("[URL B]");console.log("http://localhost:3978/test-get")console.log("[URL C]");console.log("http://<Your Localhost Address>:3978/test-get");});// Listen for incoming requests.server.get('/',(req,res)=>{res.writeHead(200,{'Content-Type':'text/html'});res.write("Welcome to the start test page");res.end();});server.get('/test-get',(req,res)=>{fs.readFile("./index.html",'UTF-8',function(err,data){res.writeHead(200,{'Content-Type':'text/html'});res.write(data);res.end();});});server.post('/test-post',(req,res)=>{res.send({TestBody:"Test Post Response Body"});res.end()});

server.get() という風に書いている部分が 2 箇所あるかと存じますが、server.get('/',...) と書かれているところと、server.get('/test-get',...) と書かれているところがありますね。

'/' のエンドポイント方ではプログラム内で用意した文字列を返していて、'/test-get' のエンドポイント方では index.html というファイルを readFile していることが何となくわかるかなと思います。 (細かい話は node.js の話になるので、何となくで感じていただけたらと。)

HTML 編集

index.html の中身を少し編集してみてください。以下が標準状態(というか私が用意したまんまの状態)です。

の間とかを自由に編集した上で、/test-get にアクセスしてみましょう。
<html><p>Hello from index.html</p></html>

localhost の IPアドレスで実行

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

ipconfig

image.png

ここで出力される IPv4 アドレスを使用して http://:3978 にアクセスしましょう。
すると、最初にアクセスしたのと同じページにアクセスできます。

ローカルで POST 実行

先ほど実行したのは HTTP の GET リクエストです。POST リクエストに関しても試してみましょう。

落としてきたファイル群の中にある test.http というファイルを VSCode で開きます。
その後、ファイルの一番上にある "Send Request" のボタンをクリックしてみましょう。
すると以下の画像のようになります。

image.png

画面の右側は POST リクエストを送信した結果になります。
今は同じ PC でserverを立ててリクエストを送信してますが、実際には異なる serverに POST リクエストを送ることで、処理を分けたりすることができます。

ちなみに、実際には POST の際に何等かのデータを追加して送ることで、そのデータを基にサーバー側で処理をしてもらうってことが多いです。例えば、IoT システムである地点で取得した温度のデータを POST リクエストでサーバーに投げると、サーバー側でデータベースに保存する処理をする。等が考えられます。

スマホからアクセス(GET リクエスト)

先ほどまでは同じPC から HTTP リクエストを送信していました。今度はスマホを使ってリクエストを送ってみましょう。

サーバーのアプリは起動したままで次の処理へ入りましょう。

Wi-Fi に繋いで

まずはスマホを PC と同じ Wi-Fi に接続させた状態で、http://:3978 (もしくは /test-get) にアクセスしてみます。

image.png

こんな感じで PC で試した時と同じ表示がされますね。

Wi-Fi から外して

次に、スマホの Wi-Fi をオフにして同じページを開いてみます。
すると、以下のようになるかと思います。

image.png

さて、ここで先ほど PC で確認したページに繋がらない事象が発生するかと思います。
なんででしょうか?

はい、これはスマホとサーバ(PC) が異なるネットワークに存在しているために発生しています。
Wifi に接続していた際には同じネットワーク内に存在していたので、ローカルの IP アドレスでアクセス出来ていたのですが、今スマホは Wifi に接続されていません。

筆者が雑に作ったイメージ図です。イメージ図です。(大事なことなので)

オンプレでの実行時はこんな感じです。
image.png

IP アドレスからスマホ君がどこへアクセスしたいのかをお家の Wifi を管理してくれてる機器がうまく制御してくれます。

次に、Wifi から外した時のイメージ図です。イメ(ry


image.png

ここで問題なのは、この IP アドレスはローカルなネットワークでしか理解できないものですので、異なるネットワークから接続しようとしてもどこにあるのか分かりません。東京のおまわりさんに奈良の住所を聞いても場所のイメージがつかないようなものです(?) なお、実際にはサーバーに繋がろうとスマホ君が頑張っていたことすら、サーバー君には届きません。

逆に言うと、何等かの方法で別のネットワークからでもアクセスできるところにサーバー君がいれば、スマホ君からアクセスができますね。

image.png

このことから、Web アプリを作成した際にはアプリの公開方法を意識する必要があるということが分かりますね。例えば、自社の人のみが使用する Web アプリであれば自社のネットワークにいたらアクセスできることが目的になるかもですが、一般の人が利用するアプリ等であればインターネット等で接続できるようにしなければいけません。

今回はその解決策の一つとして、クラウドサービスを使います。

Azure 使う

いよいよクラウドを使います。「ここまで長かったな。。。」って思った方もいらっしゃるかと思いますが、あと一息ですので一緒にがんばりましょう。僕も書いてて疲れてきましたががんばります。

リソース作成

Azure に作成したアカウントでログインして、Portal の上の検索バーで「App Service」って検索して、新規に App Service のリソースを作成します。
image.png

公開、ランタイム スタック、オペレーティング システムは以下に揃えてもらうと確実かなと思います。

image.png

リソース名やリソースグループ等はご自由に編集してください。そしたら、作成まで進めてください。

Deploy

先ほど作ったリソースに対して作成したアプリを Deploy します。もし気になる方は以下も参考にしてください。

https://docs.microsoft.com/ja-jp/azure/app-service/quickstart-nodejs?pivots=platform-windows

VSCode でプロジェクト一式を開きましょう。先ほど npm start 等のコマンドを入力した時のように、
Powershell 等で該当のディレクトリ(フォルダ階層) にいる場合は以下のコマンドでも開けます。

code .

(Code は VSCode のコマンド、"." は現在のディレクトリのファイル全てを指定しているイメージです。)

もしなんらかの理由でコマンドが実行できない人は以下のようにVSCode を開いてからフォルダを指定して開いてください。
image.png

左側から、追加した Azure の拡張機能をクリックして、画像のように作成した App Service のリソースを見つけます。サブスクリプション等があっているかを確認して探しましょう。(最初は Azure へのログイン等も要求されるかと思います。)

image.png

そこで右クリックをして「Deploy to Web App...」 を実行します。
image.png

その後、 Deploy するか等の確認がされますので従ってクリックをして Deploy 完了まで待ちましょう。

App Service 上の Web アプリにアクセスする

さて、Deploy が完了したらいよいよ大詰めです。実際に App Service に Deploy したアプリにアクセスしてみましょう。

該当の App Service リソースを開くと、以下のように URL の欄があるのでこちらをクリックしてもらうと
image.png

先ほどローカルで実行していたページを同じページが開けます。
image.png

他のエンドポイントに関しても以下の通り!
image.png

スマホからアクセス

今度はスマホのWi-Fi をオフにして App Service へアクセスしてみましょう。ローカルで実行していた時にはアクセスできなかったのが、アクセスできているのではないでしょうか。


image.png

こんな風にパブリックにアクセスできる(異なるネットワークからアクセスできる)リソースを用意できるのはクラウドの魅力の一つかと思います。(この一文のためにかなり回り道をしました)

HTML 編集

こちらは任意ですが、ローカルの時同様に HTML を編集したい場合には、以下の App Service Editor を使用できます。実際には、こちらはプレビュー機能であるためお勧めはできませんが、そもそも本来は*開発はローカルで行って、エラー等が出ない状態にしてから クラウドへ Deploy *というイメージが多いかなとかと思います。(CI/CD とかそういう話は抜きにしてます。)

image.png

クラウドに POST

念のために POST も試してみましょう。ローカルの際と同様に .http ファイルから POST リクエストを送ってみましょう。

先ほどは http://localhost:3978/test-postだったかと思いますが、今回は先ほどの https://.azurewebsites.net/test-post に対してリクエストを送ってみて、先ほどと同様の動作を確認してみてください。

まとめ

今回はクラウドを体験しやすいものとして、サーバアプリ(node.js 製)をローカルとクラウドのどちらでも実行してみるハンズオンとしてみました。もちろん、クラウドの利点は他にもたくさんありますが、イメージの一端でも伝わってますと幸いです。

クラウドのメリットとして今回の例では、クラウドを使うとサーバーアプリにアクセスしやすかったり、手元でサーバを起動する時のように常に手元の PC でサーバアプリを起動する必要等がない点がありましたが、実際にはそもそも個人手では開発が難しい機能等をクラウドを利用すると開発のハードルが低くなるといったケースもあります。

ただ、オンプレミスの方が良い場合等もあるかと思います。今回のハンズオンでいうと誤差の範囲化と思いますが、ネットワークの距離的な問題から処理の速度がオンプレの方が早いこともあります。また、社外につなげないような環境であればオンプレの環境の方が良いこともあります。

結局のところ、技術に至高なんてものは存在しないのかなと思います。ベストプラクティスなんて状況に応じて変化すると思います。なので、クラウドやオンプレ等の単語で反応して否定するよりは、それぞれの強みを理解して状況に応じて使い分けるのが大切なのかもしれませんね。(雑なまとめ)

とりあえず、僕としては皆さんが楽しく学習出来たら良いなって思ってます。では。

json-serverでREST APIをmockする

$
0
0

はじめに :sleepy:

JSON Server

https://github.com/typicode/json-server

  • 簡単なものならコーディング不要でサクッとAPIをモックできるNode.jsのライブラリ
  • 詳しく使い方を知りたい場合は上記リポジトリのREADMEを読んだほうが良い

まえがき

まだAPIが用意できていないけど、フロント側の実装を進めたいときに便利です。
本記事ではサクッと使える簡単なモックと、応用として以下2つの方法を記載したいと思います。

  1. POSTリクエストで任意のレスポンスを返す
  2. サーバーサイドエラーのモックする

サクッと使う

任意のディレクトリを作成し移動後、 json-server をインストールする

$ npm install json-server --save-dev

db.json を作成し、モックしたいデータを挿入

db.json
{"molcars":[{"name":"ポテト","favoriteFood":"ニンジン"},{"name":"シロモ","favoriteFood":"レタス"}],"episodes":[{"id":1,"title":"渋滞は誰のせい?"},{"id":2,"title":"銀行強盗をつかまえろ!"}]}

これでおわり!
あとは以下コマンドを叩いて json-server を起動し……

$ json-server --watch db.json

curlなりなんなりで、このように db.json に記載したデータが返却されます。

$ curl -X GET 'http://localhost:3000/molcars'[{"name": "ポテト",
    "favoriteFood": "ニンジン"},
  {"name": "シロモ",
    "favoriteFood": "レタス"}]
$ curl -X GET 'http://localhost:3000/episodes'[{"id": 1,
    "title": "渋滞は誰のせい?"},
  {"id": 2,
    "title": "銀行強盗をつかまえろ!"}]

応用

上記だけじゃ機能として物足りない場合、
json-server をモジュールとして使用することでほしい機能を追加できます。

json-server をモジュールとして使う

公式のREADMEにあるシンプルなコードです。

server.js
constjsonServer=require('json-server')constserver=jsonServer.create()constrouter=jsonServer.router('db.json')constmiddlewares=jsonServer.defaults()server.use(middlewares)server.use(router)server.listen(3000,()=>{console.log('JSON Server is running')})

以下コマンドで起動可能

$ node server.js

この時点でできることはサクッと編と基本的に同じで、
上記コマンドで起動したあとにcurlするとdb.jsonの値が同じように返却されます。

というわけで、上記のコードにほしい機能を追加していきましょう。

POSTリクエストで任意のレスポンスを返す

サクッと編で作成したモックでは、
POSTでリクエストを送ると実際に以下のようなレスポンスが返却され、
なおかつこのレスポンスと同じデータが db.jsonに勝手に挿入されます。

{"id":2}

(idの値は自動でインクリメントされます。)

なのでPOSTでリクエストした際のレスポンスを設定したい場合や、
勝手に db.jsonに値を追加してほしくない場合は
POSTリクエストを server.js内でGETとして処理するように変更します。

server.js
constjsonServer=require('json-server')constserver=jsonServer.create()constrouter=jsonServer.router('db.json')constmiddlewares=jsonServer.defaults()server.use(middlewares)/** ↓ POST を GET として処理する場合はここを追加 ↓ */server.use(jsonServer.bodyParser)// POST, PUT, PATCH を扱うために必要server.use((req,res,next)=>{if(req.method==='POST'){// POST のリクエストを GET に変換req.method='GET'}next()})/** ↑ POST を GET として処理する場合はここを追加 ↑ */server.use(router)server.listen(3000,()=>{console.log('JSON Server is running')})

あとは先程と同様に起動して

$ node server.js

curlでレスポンスが返ってくることが確認できます。

$ curl -X POST 'http://localhost:3000/molcars'[{"name": "ポテト",
    "favoriteFood": "ニンジン"},
  {"name": "シロモ",
    "favoriteFood": "レタス"}]

サーバーサイドエラーのモック方法

公式のREADMEに記載されていますが、
レスポンスを変更したい場合は router.render メソッドを上書きします。

任意のステータスコードおよびエラーメッセージを返す場合は
server.jsを以下のように変更します。

server.js
constjsonServer=require('json-server')constserver=jsonServer.create()constrouter=jsonServer.router('db.json')constmiddlewares=jsonServer.defaults()server.use(middlewares)server.use(router)server.listen(3000,()=>{console.log('JSON Server is running')})/** ↓ サーバサイドエラーをモックしたい場合はここを追加 ↓ */router.render=(req,res)=>{// ステータスコードを設定res.status(500).jsonp({error:"PUI PUI"})}/** ↑ サーバサイドエラーをモックしたい場合はここを追加 ↑ */

これも同様に起動すれば

$ node server.js

叩いた際に ステータスコード500
エラーメッセージ「"error": "PUI PUI"」が返却されるようになります。

$ curl -X GET 'http://localhost:3000/molcars'{"error": "PUI PUI"}
Viewing all 8837 articles
Browse latest View live