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

[Node.js] express + nodemon + BrowserSync でゲボ楽コーディング

$
0
0

はじめに

expressを使ってBrowserSyncを使う記事が少なかったので書きます。
nodemon + BrowserSyncでブラウザノータッチの楽々コーディングを目指そう。

方法

  1. expres側ファイルをnodemonで監視(3000portで起動)
  2. BrowserSync を 4000 番ポートで起動、nodemonに接続

これによりクライアント側のファイルはBrowserSyncでブラウザをリロード
nodemonによるサーバ再起動は、再起動後にBrowserSync に通知してもらえるようにする。

前提

  • node + expressは導入済み
  • Nodeの側のポートは3000に指定

導入

browser-syncのインストール

$ npm install --save-dev browser-sync

インストールが終わってからbrowser-syncのコンフィグファイルを生成

$ npx browser-sync init

bs-config.jsが作られるので、以下のように一部を編集
プロキシをhttp://localhost:3000に指定することで連携可能。
今回はカスタムテンプレートにEJSを使用するために.ejsを指定しているが、適宜対応してください。

bs-config.js
"files":["**/*.js","**/*.ejs","**/*.css"],~中略~"proxy":"http://localhost:3000","port":4000,

次にnodemonのインストール

$ npm install -g nodemon

ここまでくればあとはどちらも起動するだけで終わりだが、どうせならまとめて起動したい。
ここでひと手間を加える。

npm-run-allのインストール

$ npm install --save-dev npm-run-all

package.jsonの編集(抜粋)

package.json
"scripts":{"start":"npm-run-all --parallel start:*","start:nodemon":"nodemon ./bin/www","start:sync":"browser-sync start --config bs-config.js"},

あとはnpm startで楽々開発。

package.json の解説

動きますね!終わり!でもいいがnpm-run-allを使った記述が多少わかりずらいので解説

npm-run-allの詳しい挙動に関してはggってもらって・・・
npm-run-allはシーケンシャルとパラレルの二つの指定方法があります。

今回はparallelを指定しなければ、nodemon or browser-syncどちらかしか動きません。
nodemonbrowser-syncも一度呼び出すと永続するので・・・

"start": "npm-run-all --parallel←コレ start:*",

start:*に関しては後ろ2行の:以下を表しています。

 "start:nodemon←コレ": "nodemon ./bin/www",
 "start:sync←コレモ": "browser-sync start --config bs-config.js"

他にもいろいろ応用できそう。

参考記事


Node.jsをインストール(nodebrewでバージョン管理)

$
0
0

本来の目的:ローカル環境でES6を使用

node.jsのバージョン管理ツールnodebrewをインストール

※メリット:複数のnode.jsのバージョンを簡単に切り替えられる。

brewがインストールされているか確認

$brew-v
【実行結果】インストールされている
Homebrew2.2.6Homebrew/homebrew-core(gitrevisionba38;lastcommit2020-02-28)

nodebrewのインストール

$ brewinstallnodebrew
【実行結果】
UpdatingHomebrew...==>Auto-updatedHomebrew!Updated1tap(homebrew/core).==>NewFormulaeabseilhdf5@1.10publisharchiverhdtqpazcopyhsdsealbnfckillswitchswift-formatccheckmockoloswift-shcdk8smtoctlxcontainer-structure-testnefvpn-slicedhall-yamlnewrelic-clixclogparserforceclioilzimgit-trimopenlibm==>UpdatedFormulaenodeless(省略)Removing:/Users/lancai/Library/Logs/Homebrew/yarn...(100B)Removing:/Users/lancai/Library/Logs/Homebrew/autoconf...(64B)Removing:/Users/lancai/Library/Logs/Homebrew/node...(64B)Removing:/Users/lancai/Library/Logs/Homebrew/rbenv...(64B)Pruned1symboliclinksand2directoriesfrom/usr/locallancai@ojaDesktop%

2分ほどでインストールが完了。
※10分以上かかる場合もあるとのこと

nodebrewのバージョン確認

$nodebrew
【実行結果】
nodebrew1.0.1Usage:nodebrewhelpShowthismessagenodebrewinstall<version>Downloadandinstall<version>(frombinary)nodebrewcompile<version>Downloadandinstall<version>(fromsource)nodebrewinstall-binary<version>Aliasof`install`(Forbackwordcompatibility)nodebrewuninstall<version>Uninstall<version>nodebrewuse<version>Use<version>nodebrewlistListinstalledversionsnodebrewlsAliasfor`list`nodebrewls-remoteListremoteversionsnodebrewls-allListremoteandinstalledversionsnodebrewalias<key><value>Setaliasnodebrewunalias<key>Removealiasnodebrewclean<version>|allRemovesourcefilenodebrewselfupdateUpdatenodebrewnodebrewmigrate-package<version>InstallglobalNPMpackagescontainedin<version>tocurrentversionnodebrewexec<version>--<command>Execute<command>usingspecified<version>Example:# installnodebrewinstallv8.9.4# use a specific version numbernodebrewusev8.9.4

私のバージョンは8.9.4みたいです

Node.jsのインストール

実行環境の確認
$echo$SHELL
【実行結果】
/bin/zsh

/bin/zshの場合は以下を入力

$echo'export PATH=$HOME/.nodebrew/current/bin:$PATH'>>~/.zshrc

〜ここまでインストール準備完了〜

以下を一つずつ実行

$source~/.zshrc
$nodebrewsetup
実行結果
Fetchingnodebrew...Fetchingnodebrew...Installednodebrewin$HOME/.nodebrew========================================Exportapathtonodebrew:

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

引き続き以下を実行

$ nodebrewusestable
実行結果
usev12.16.1
$node-v
実行結果
v12.16.0

Node.jsのバージョンが表示されたので無事にインストール出来たようです。

jestでモックしてみたメモ

$
0
0

レガシーコードのテストをjestに移行していた時に、
jestだとどうやってモックしたり、追跡したりするんだ?となったのでその時のメモ

最初に

相当アホなところでハマったのだが、jest はnamespaceをそのまま読み込むため以下のようの読み込まないといけない。

import'jest'// OKimportjestfrom"jest"// NGjest.xxxx()

特定の関数をモックする

関数にもろもろについてモックの仕方です。

テスト用のモック関数の作成

constmockFunc=jest.fn().mockImplementation(()=>return"mock func");console.log(mockFunc());// mock func

関数自体のモックは jest.fn()に集約されており、単純に何か値を返すのみの関数は mockImplemantionの引数で定義します。
また、mock関数の引数や、どういった値を返したかの検証も行えます。

関数の動作の検証

引数の検証

実際にモックした関数の引数を見たい場合はこんな感じでmock.calls を使います

constmockFunc=jest.fn().mockImplementation((message:string)=>{returnmessage;});mockFunc('test1');mockFunc('test2');console.log(mockFunc.mock.calls);// [ ['test1'], ['test2']] 

戻り値の検証

戻り値の場合はmock.resultsを使います。

constmockFunc=jest.fn().mockImplementation((message:string)=>{returnmessage;});mockFunc('test1');mockFunc('test2');console.log(mockFunc.mock.results);/*
[
  {
    type: 'return',
    value: 'test1',
  },
  {
    type: 'return',
    value: 'test2',
  },
];

*/

value は実際に返した値で、
typeはその値が正常リターンか、エラーかを判定します。

正常の場合は return
エラーがスローされた場合は throw
となります。

また、 imcompleteというケースがありますが、これはよくわからないので省略します。

後処理

テストの後処理は2種類あり、 関数のモック自体を抹消する場合と、関数の引数などの追跡結果を抹消する場合があります。

constmockFunc=jest.fn().mockImplementation((message:string)=>{returnmessage;});mockFunc.mockClear()// どういった引数を受取、どういった値を返したかの計測結果をリセットmockFunc.mockReset()// 実際に実装した関数や戻り値の設定をリセット

特定のオブジェクトに生えている関数を追跡、モックする

追跡対象を指定

constspy=jest.spyOn(targetObject,"do");// オブジェクトの指定とそこから生えている関数を指定// 関数実行処理expect(spy).toHaveBeenCalled();// 関数が実行されたかどうかを検証

指定した関数をモック関数にする

constspy=jest.spyOn(targetObject,"do").mockImplemention(()=>"spy");

↑のようにすると、指定したオブジェクトの関数は、mockImplementionの中で定義した関数に差し替えられます。
なお、mockImplementionの中には先程解説した jest.fnを渡すこともでき、その場合は引数などの検証も行えると思います(未検証)

オマケ 現在時刻のモック

特定の時刻でポイントが失効するかどうかをチェックしたい場合に現在時刻をモックする必要があったのでその時のことも書いておきます。

重要なことは、日付を扱うパッケージオブジェクト(moment, dayjsなど)はjavascriptのDateオブジェクトに依存しているため、Dateオブジェクトをモックすれば現在時刻系は騙せます。

なので、

  • jest で Dateオブジェクトをモックする
  • mockDateを使う
  • 自分でDateオブジェクトをモックする(レガシーコードはこれをやってた)

個人的に、mockDateを使うのが良いかなと思います。使いやすいしリストアなどもやりやすい他、
ドキュメントも充実しているので、情報共有もしやすいです。

最後に

時刻関連のモックをしらべるのに一番時間がかかりました。
Dateオブジェクトをいじればいいみたいな結果は出てくるのですが、なぜそれが必要なのかという理由が納得できず、
momentの初期化処理のコードを見に行ってDateオブジェクトに依存しているとわかりました。

それでは、良いjestライフを

Node.js用QualityForward SDKを使ってテストフェーズを作成する

$
0
0

QualityForwardはクラウドベースのテスト管理サービスです。APIを公開しており、テスト管理に関するデータのCRUD操作ができるようになっています。SDKとしてはNode.js、Python、そしてGoogle Apps Scriptを作成中です。

Node.js SDKについてはデータの取得系は一通り実装されています。今回はデータの追加、テストフェーズの作成について紹介します。

QualityForward用Node.js SDKを使う

Node.js SDKはgoofmint/qualityforward-nodeにて公開しています。npmで公開していますので、インストールは簡単です。

npm i qualityforward -S

初期化

初期化はAPIキーを適用して行います。

client=newQualityForward('YOUR_API_KEY');

テストフェーズの作成

まずテストフェーズオブジェクトを作成します。

consttestPhase:TestPhase=client.TestPhase();

値を設定する

次に値を設定します。プロジェクトID、名前、開始日、終了日は必須です。

testPhase.project_id=748;testPhase.name='test';testPhase.start_on=newDate();testPhase.end_on=newDate();

さらに例えばBTS連携としてRedmineを用いる場合には次のように登録します。

testPhase.bug_tracking_system='redmine';// redmineまたはjiraを指定testPhase.redmine_base_url='https://example.com';// ベースURLtestPhase.redmine_issues_url='https://example.com';// バグ曲線、グラフデータ取得用URLtestPhase.redmine_latest_issues_url='https://example.com';// 最近のインシデント取得用URL

テストスイートバージョンを登録する

テストフェーズと連携するテストスイートバージョンを指定します。これは複数登録可能です。

consttsv=client.TestSuiteVersion();tsv.id=13290;testPhase.test_suite_versions.push(tsv);

保存する

最後に保存します。問題があればエラーが発生するので、try〜catchで捕捉できます。

awaittestPhase.save();console.log(testPhase.id);

まとめ

既存のシステムからテストケースを移行する際にAPIを利用できます。入力が面倒な場合、APIを使えば一気に処理できますので、Node.jsを社内システムで使っている場合には試してみてください。

QualityForward

npm upTypeError [ERR_INVALID_ARG_TYPE]

$
0
0

状況

以下のようなメッセージが出たので実行してみました。

information.sh
│   New patch version of npm available! 6.14.1 → 6.14.4          │
   │   Changelog: https://github.com/npm/cli/releases/tag/v6.14.4   │
   │               Run npm install-g npm to update!                |   

update.sh
$ Run npm install-g npm

updateが完了してgulpを実行しようとしたところ
変更していないタスクにて以下のエラーが発生。

error.sh
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type object

解決方法

邪道ではありますが
gulp-combine-media-queries/index.jsの
152行目付近の以下の部分をコメントアウトします。

index.js
file.contents=newBuffer(cssJson);

自分の場合globをインストール(npm i glob)しており
gulp-combine-media-queriesがインストールされていた。
何度か踏んでいるバグだったので割とすぐ気がつけてよかった。
上記コメントアウトでタスクが実行できました。

原因

今回Run npm install -g npmの実行で
gulp-combine-media-queriesのjsファイルの
コメントアウトが外れる(上書きされる?)という事象に出会うことが出来ました。
たまたま原因が見つかったからよかったものの
エラーが出ていたタスクや直近でgulp-combine-media-queries関連の
変更はしていなかったのでハマってもおかしくない状況だったと思います。
このエラーはissueは立っているものの放置され
新しいものもフォークされているようです。
https://github.com/konitter/gulp-combine-media-queries/issues/19
しかしながらプラグインが依存しているという状態だと
そちらが変更されないといけない状況ですから応急処置として前述の回避策をしています。
gulpファイルの書き方で解消できるかもしれませんが
何かもっと良い解決方法をご存知の方はコメントいただけましたら嬉しいです。

chromeで401レスポンスが返ってきたときの不具合

$
0
0

背景

https://www.nnn.ed.nico/questions/14833
n予備校の教材の通りに実装を進めていたところ、このリンクと同じ状況に遭遇

問題

chromeに限り、以下のコードで表示されるはずのログアウトしましたという文とリンクが表示されない。

functionhandleLogout(req,res){res.writeHead(401,{'Content-Type':'text/html; charset=utf-8'});res.end('<!DOCTYPE html><html lang="ja"><body>'+'<h1>ログアウトしました</h1>'+'<a href="/posts">ログイン</a>'+'</body></html>');}

原因

chromeのバグ
https://bugs.chromium.org/p/chromium/issues/detail?id=992639

解決

  • とりあえず別のステータスコードを変える
functionhandleLogout(req,res){console.log('handleLogout');res.writeHead(400,{'Content-Type':'text/html; charset=utf-8'});res.end('<!DOCTYPE html>'+'<html lang="ja"><body>'+'<h1>ログアウトしました</h1>'+'<a href="/posts">ログイン</a>'+'</body></html>');}
  • (ブラウザを変える)

追記

教材にこのエラーについての解決方法が追記されていた。
解決方法は、ステータスコードを302に書き換えること。

https://developer.mozilla.org/ja/docs/Web/HTTP/Status
より、

302 Found
このレスポンスコードは、リクエストされたリソースの URI が一時的に変更されたことを示します。

Qiitaに投稿した記事をいい感じにExportする君を作った

$
0
0

結論ファースト

作ろうと思ったきっかけ

  • 最近Qiitaがいろいろと話題なので、自分の記事をExportしたいなと思った
  • 朝起きて、突如やろう!となった(出勤前までに)

実現したかった"いい感じ"とは

  • 記事はマークダウンを取得すること
  • 記事内に、Qiitaにアップロードした画像もダウンロードしてくること
  • 記事ごとにディレクトリを分けて写真と記事のセットをわかりやすくすること

所感

  • 作業時間が短かったため、リファクタリングが追いつかなかったしテストとかはもちろんない
  • 作業時間の大体は正規表現に奪われてしまった

Webサイトを運営しているミニマリストがインストールしている最低限必要なアプリ達

$
0
0

Overview

シンプルであることに越したことはない。
シンプルなら環境の移行や再構築も苦にならない。
シンプルなら必然的にミスする確率も低減する。
今回は環境構築メモの役割も含めて、Webサイト運営に使用しているアプリを公開しておきます。

Target reader

  • シンプルかつ低コスト&高い可用性を持つWebアプリを運用したい方。
  • Webサイトを作る上で最低限何を勉強しないといけないか知りたい方。

Prerequisite

  • OSはWindows
    • Macは1社に依存することからリスクヘッジのためWindows
    • ただし、LinuxコマンドがメジャーなのでWindowsで実行する場合にググらないといけないことがある。 (WindowsのLinux環境であるWSL2が一般的になれば格差は是正されるかもしれない)
  • 言語はNode.js
    • フロントエンドがJavaScript一択なので、バックエンドも同一言語ならパッケージも共有でき効率的。
    • クラウドベンダーのFaaS(Functions)をみた場合、Node.jsは各社採用言語の中で1,2位に属している。
  • クラウドはFirebase(Google Cloud Platform)
    • 個人でサービス提供するには可用性が命。その上でJavaScriptのコンテンツを配置するだけでいいFirebase Hostingは最善の一手。
      • PWA化することで、キャッシュ優先利用により更に可用性を高めることが可能。
      • データ転送量による完全従量制のため、ミニマムスタートにもってこい。
    • そのほかオフライン対応の完全従量制DBであるFirestore等がそろっている。
    • アプリが複雑化した際はGCPが控えているのでAWSやAzureにも決して見劣りはしない。

Body

全てのアプリ.png

Windowsにインストールしているアプリ

Chrome

https://www.google.com/intl/ja_jp/chrome/

文句なしのブラウザシェアNo.1なので、Chromeで開発しないWebアプリはありえない。

Git

https://gitforwindows.org/

Gitはソース管理のために利用する。
GitというよりGitHubはGCPにデプロイするためのハブになっているので不可欠。
GitHubに障害がおこるとデプロイできなくなるためもはや仕事不可。
(Gitはローカルで更新できるのでソースの修正を記録し続けることは可能)

Node.js

https://nodejs.org/ja/

フロントエンドもバックエンドもJavaScript言語で書けてしまうJavaScriptランタイム。
バックエンドは別言語でもいいが、あえて別の言語にする理由がないならJavaScript一つで十分。

Visual Studio Code

https://azure.microsoft.com/ja-jp/products/visual-studio-code/

Visual Studio Codeはソースコード書いたり、デバッグしたり、開発時に利用する。
WebアプリのIDEのスタンダードになりつつあるかな?
Windows開発向けに作られたVisual Studioが動作が重く、ダウンロードサイズも大きかったがこいつは軽量で人気が高い。
拡張機能も充実しており、IDEとの連携でVSCodeがないということは見たことない。

[optional]Google Cloud SDK

https://cloud.google.com/sdk/install?hl=ja

今のところgcloud functions deployコマンドで必要になるが、Cloud Buildを利用してデプロイしているだめインストールされてなくても問題ない。
ただし、各プロダクトのコマンドを使うことになるはずなので、必要になったら入れたほうがいい。
入れなくてもCloud Shellがあるため乗り越えられるかもしれないが。

[optional]Firefox

https://www.mozilla.org/ja/firefox/new/

ブラウザシェアはChromeが圧倒しているが、Firefoxも一定程度ユーザーがいる。
そのため、Firefoxでの動作確認もしておきたいところ。

[optional]Edge

https://support.microsoft.com/ja-jp/help/4501095/download-the-new-microsoft-edge-based-on-chromium

Edgeのシェアはかなりすくないが、Chromiumベースとなり標準でインストールされるようになったら今後無視できなくなるかも?
ChromiumベースでChromeと違いも少なくなると予想できることから、WindowsPCをある程度ターゲットにするなら動作確認したいところ。

[optional]Slack

https://slack.com/intl/ja-jp/downloads/windows

個人で開発しているとPC上でコミュニケーションは取る必要がないため、PCへのインストールは必須ではない。
ただし、通知はよく使うはずなので、スマホへのインストールは必須。

npmでグローバルにインストールしているパッケージ

他にtoとupdateというパッケージがインストールされていた。
手動でインストールした記憶はないが、何かのインストールでバンドルされるなら消さないほうが吉。

firebase-tools

https://firebase.google.com/docs/cli?hl=ja

firebase関連のコマンド実行の際に必要。
現状だとFirebase Hostingにデプロイする際に使用している。

npmで各プロジェクトにインストールしているパッケージ

React

https://ja.reactjs.org/docs/create-a-new-react-app.html

個人開発に重要なSPAで今構築するならVue.jsかReact。
私は仕事でReactを経験したので、それを引き継いでいるがVue.jsの採用を検討したいところ。

Material-UI

https://material-ui.com/

Reactだけでは生のHTMLで記述するため、見た目がかなり貧相になる。
そのため、見た目をよくするために必要なパッケージとして有力なのがMaterial-UI。
基本的なサンプルソースがそろっており、カスタマイズもしやすいので非常に使いやすい。

REACT ROUTER

https://reacttraining.com/react-router/web/guides/quick-start

WEBのページ遷移を管理するためライブラリ。
パスとそれに対応したコンポーネントを指定することで簡単にページ切り替えができる。
コードが多くなるとコード分割が必須になるが、導入しておくとパスごとに簡単に分割できるので便利。

VisualStudio Codeにインストールしている拡張パッケージ

Debugger for Chrome

https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome

VSCode上でChromeをデバッグするために必要な拡張機能。
個人的にはあまり使っていないが、入れておいた方がいいだろう。

Japanese Language Pack for Visual

https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja

VSCodeを日本語表記にしてくれる。

[optional]REST Client

https://marketplace.visualstudio.com/items?itemName=humao.rest-client

いろんなパラメータを含んだWebAPIをコールしたいときに便利。
個人的にはあまり使っていないが、入れておいた方がいいだろう。

[optional]DotEnv

https://marketplace.visualstudio.com/items?itemName=mikestead.dotenv

Reactで環境変数を使う際に.envというファイルを使うが、VS上で強調表示してくれるもの。
なくても支障はない。

[optional]VSNotes

https://marketplace.visualstudio.com/items?itemName=patricklee.vsnotes

MarkDown形式でメモできる拡張機能。
課題やメモ等をとにかく書き込んで使っている。
最低限のものしかインストールしていないので、最終的にこのVSNotesが何でも屋としてフォローしてくれている。

Google Chromeにお気に入りとしているサイト

Search Console

https://search.google.com/search-console/about?hl=ja

自身のサイトがGoogle検索に正しく登録されているか、ユーザーがどんな検索ワードで入ってきているか等がわかる。
Webサイトを公開するなら100%通る道。

Google Analytics

https://marketingplatform.google.com/intl/ja/about/analytics/

サイトに入ってから出るまでのあらゆる情報が収集されている。
サイトを成長させるうえで分析は効果的ゆえ、これも必ず導入したいものの一つ。

Create React App

https://create-react-app.dev/docs/getting-started/

Reactを新規で作るなら、もはやCreate React Appは必須といっても過言ではない。
Create React Appを用いれば、深い知識を必要とせずに簡単に本番向けのサイトを構築できる。

Google Cloud Platform

https://console.cloud.google.com/home/dashboard

GCPのダッシュボード。クラウドを扱う以上必須。

Firebase

https://console.firebase.google.com/

Firebaseのダッシュボード。クラウドを扱う以上必須。

Google Adsense

https://www.google.com/adsense/

Webサイトの収益化の筆頭。モバイルがApp StoreかGoogle PlayならWebはAdsense。
審査に通れば簡単に収益化できる反面、厳しい処置を受けることもある。
身綺麗な運営と理不尽と感じてもそれを受け入れる忍耐が必要。

Conclusion

インストールが必要なアプリやライブラリが20個未満でサイトの運用が可能です。
これらを理解したなら、その少し先に私がいるということです。
学習コスト高いものもありますが、低コスト&高い可用性実現のために頑張ってみてください。

便利なものはつい入れたくなりますが、依存関係を増やす以上のメリットがあるか考えてみるといいでしょう。
インストールしているものが一般的なものなら、クラウドベンダーが提供しているDockerイメージをそのまま利用できる場合もあります。
個人的には数年後、SurfaceGo持ち歩きながらVS Onlineで開発して、パワフルなノートPCを持たない人を目指しています:sweat_smile:

simple is best!
Have a great day!


Mac Node.jsのバージョン有効化する手順でvX.X.X is not installedと出力された話

$
0
0

目的

  • Node.jsをHomebrewを使用してインストール後にバージョンを有効化する際に「vX.X.X is not installed」と出力され、それを解決した話をまとめる。

実施環境

  • ハードウェア環境
項目情報備考
OSmacOS Catalina(10.15.3)
ハードウェアMacBook Air (11-inch ,2012)
プロセッサ1.7 GHz デュアルコアIntel Core i5
メモリ8 GB 1600 MHz DDR3
グラフィックスIntel HD Graphics 4000 1536 MB

エラー内容

  • インストール後に下記コマンドを実行してバージョンの有効化を行った。(インストールは正常に完了、X.X.Xはバージョン名)

    $nodebrew install-binary stable
    $nodebrew use vX.X.X
    >vX.X.X is not installed
    

解決方法

  1. 下記コマンドを実行する。

    $nodebrew --version
  2. コマンドの出力の下部にある「# install」に記載されているコマンド$ nodebrew install vX.X.Xを実行する。

    $nodebrew install vX.X.X
    
  3. 再度、バージョンを有効化するコマンドを実行する。

    $nodebrew use vX.X.X
    
  4. 下記コマンドを実行して有効化したバージョンが正しい物になっている事を確認する。

    $nodebrew ls・
    ・
    ・
    >current: vX.X.X
    

Why should you hire a dedicated node.js developer?

$
0
0

hire-Node-js-developer.png

Every business needs software to run their business in a world that is rapidly digitizing. More people prefer online monetary transactions nowadays than ever before, so business organizations also have to adapt accordingly. The technology used to build software usually keeps on evolving to make the systems more efficient. One such technology that has had a strong impact on software development is Node. Due to the several advantages it offers, many organizations are constantly investing in developing software with this technology and are keen to hire node js developers. Many of the world’s leading organizations such as PayPal, LinkedIn, Walmart, NASA, Netflix, Twitter, YouTube, Yahoo, and others currently have systems that were built using Node.

Since Node is rather new when compared to other technologies, all these major organizations had to rewrite their code in Node.js to transition to this technology. This was to achieve high performing applications and improve the overall productivity of their business.

In such a scenario, it is important for any business to consider making a transition to a node. Let’s take a deeper look into this technology and understand why it could be beneficial to hire dedicated node.js developers for your organization’s software development needs.

Why Node is being preferred?

Many application programmers use JavaScript to create software. JavaScript is loved by many programmers all around the world, because of it’s near-perfect application as a cross-platform and front-end development tool. Node.Js is essentially a runtime environment built on Google’s V8 engine and it’s a single-threaded environment that runs faster. It has a unique I/O model that makes it speedy, lightweight and efficient. This I/O model greatly increases a developer’s output.

Node has all the features essential for running a program written in JavaScript efficiently. It has a very commendable ability to use JavaScript on both the back-end and front-end parts of any application.

Due to the many advantages that node.js has over, it’s counterparts, there has been a significant rise in the demand for node.js developers. Any node.js development company would greatly benefit from hiring talented developers that specialize in Node.

Any programmer can work with node if required, however, there are several benefits of hiring dedicated node.js developers.

1. Highly Experienced: Programmers usually only have a few specific languages that they work with although it is easy to switch from one language to another. However, hiring dedicated node.js developers can make a major difference because these professionals have years of experience of dealing with various types of problems specific to Node. This can help them a lot while working on projects for high-end clients. They can come up with solutions to problems that would otherwise be very difficult for a developer who is inexperienced with Programming in Node and JavaScript.

2. Customized Applications: Developers who have years of experience with Node have a relatively much easier time customizing applications for certain projects. Web applications need to be updated and changed frequently as per the requirements. Their projects are also time-bound, so it is important that the developers working at any node js development company, deliver these projects in the expected time frame. Programmers who have spent years working with nodes usually can make the necessary customizations and updates in a short period of time, with ease.

3. Post-Development Support: After an application is developed, it sometimes needs to go through several changes to make sure that it is running smoothly. When business organizations hire a node js web development company, they can be sure of getting prompt post-development support. They can resolve any queries and even get application support from the same people who developed the application. This eliminates the possibility of any confusion or inefficiency, which might lead to product failure or waste of valuable resources.

4. Error-free applications: Hiring dedicated developers can ensure that the applications developed for your business are flawless and bug-free. Developing applications that don’t have any security flaws, or redundant code or other such elements that make the application inefficient can go a long way. Poorly developed applications usually are very uncomfortable to use and that also affects the customers. So, if the applications are developed by hiring dedicated Node.js developers, it will be faster and error-free, which will boost the overall productivity in return.

One of the best places where people can find highly qualified node.js developers is Logistic Infotech. Any business in need of a node js development company USA can hire their services and get fast robust software developed for all of their business needs. They have a team of skilled node.js developers who have a proven track record of developing flawless applications for varying needs of their customers. They provide the best in class services at very affordable rates and prioritize customer satisfaction over everything else.

Rails6でアプリ起動時にWebpacker configuration file not foundエラーが発生した時の対処方法

$
0
0

執筆背景

scaffoldを使って簡単なアプリを作ろうと以下のコマンドを打ち込むと、Webpackerがインストールされていないというエラーが発生したため、記述しておこうと思う。

$ rails new app_name
$ cd app
$ rails g scaffold post content:text
$ rails s

(中略)
Webpacker configuration file not found /Users/ユーザ名/app_name/config/webpacker.yml.
Please run rails webpacker:install 
Error: No such file or directory 
@ rb_sysopen - /Users/ユーザ名/app_name/config/webpacker.yml 
(RuntimeError)

ちなみに、このときのrubyのバージョンは2.7.0、railsのバージョンは、6.0.2.2です。

結論

このエラーは、webpackerがインストールされていない場合に起こるエラーみたいです(rails6からwebpackerが標準になったため)。

webpackerのインストールには、Node.jsとYarnのインストールが必要で、これらをインストールした上でwebpackerをインストールすると解決します。

作業内容

Gemfileを確認し、gem 'webpacker'の記述を確認。

Gemfile
gem'webpacker','~> 4.0'

bundle installしたのち、webpackerをインストールしようと試みるもNode.jsがインストールされていないと怒られる。

$ bundle install
$ rails webpacker:install
sh: node: command not found
sh: nodejs: command not found
Node.js not installed. Please download and install Node.js https://nodejs.org/en/download/

Node.jsをインストールしたのち、再度webpackerのインストールを試みると、Yarnをインストールしろと怒られる。

$ brew install node
(中略)
==> node
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d

$ rails webpacker:install
Yarn not installed. 
Please download and install 
Yarn from https://yarnpkg.com/lang/en/docs/install/

Yarnをインストールしたのち、再度webpackerのインストールを試みたところインストールすることができた。

$ sudo npm install -g yarn
added 1 package in 3.509s

$ yarn -v
1.22.4
$ yarn install
success Saved lockfile.
✨  Done in 3.49s.

$ rails webpacker:install
✨  Done in 6.34s.
Webpacker successfully installed 🎉 🍰

アプリを再起動。

$ rails s
Use Ctrl-C to stop
Started GET "/posts/index" for ::1 at 2020-03-28 18:06:09 +0900

うまくいった!
スクリーンショット 2020-03-28 18.07.56.png

npmって?

$
0
0

npmって?

node package manager

Node.jsで使うパッケージを管理するために使う
Nodeをインストールすると一緒にインストールされる

npmのインストール

僕はMacOSにnodebrewでインストールした

nodebrewはNode.jsのバージョン管理システム
Homebrewでインストールする

$ brew install nodebrew
$ echo "export PATH=$HOME/.nodebrew/current/bin:$PATH" >> ~/.bash_profile
$ source ~/.bash_profile
$ which nodebrew

これでnodebrewのパスが表示されればOK

この後,nodeをインストールして,その後npmをインストールする

npmコマンド

インストールディレクトリを確認

npm root

「福井県オープンデータ ごみ収集日一覧CSVをJSONに変換するツール」README

$
0
0

※この記事は、私がGitHubに公開しているnode.js製ツール「福井県オープンデータ ごみ収集日一覧CSVをJSONに変換するツール」のREADMEを転載したものです。
解説は「恋に落ちるコード.js」の絵子と樹里です。


福井県オープンデータ ごみ収集日一覧CSVをJSONに変換するツール

福井県オープンデータライブラリ」で公開されている、県内17市町の「ごみ収集日一覧」データの形式を、CSV(Shift-JIS)からJSONに変換します。

Description

樹里「というわけで、福井県内自治体のごみ収集日一覧JSONデータを作成するアプリを作ってみた」
絵子「ほう。なんでまた突然」
樹里「それがな、久しぶりに福井県オープンデータに公開されてるデータを使って、アプリでも作ってみようとしたんだがな」
絵子「福井県は昔からオープンデータの公開に熱心だよね」
樹里「で、ごみ収集日一覧のデータを見てみたんだが、なんとShift-JISのCSVなんだよ。この令和の時代に」
絵子「うーん。確かにそのままだと扱いにくいよね」
樹里「Shift-JISのCSVなんだよ。この令和の時代に
絵子「2回言わなくていいよ。あと太字にしなくてもいいよ」
樹里「これではどうしようもないので、まずはちゃんとしたUTF-8のJSONに変換するツールから作ってみたわけだ」
絵子「なるほど。経緯はよくわかった」

Usage

樹里「使い方は簡単。Node.js製のアプリなので……」

git clone https://github.com/8amjp/fukui-opendata-gomisyusyubi-json.git
cd fukui-opendata-gomisyusyubi-json
npm install

樹里「上記のコマンドでインストールして、」

node index.js

樹里「と実行すれば、distディレクトリにJSONデータが出力される」
絵子「あら本当に簡単」
樹里「じゃあ、アプリがどういう動きをするのか解説しよう」

index.js

樹里「まずは、メインとなるコードだ」

index.js
/*
  「福井県オープンデータライブラリ」の「ごみ収集日一覧」ページで公開されている
  収集日のCSVデータ(Shift-JIS)をJSONに変換します。
*/constscraper=require('./lib/scraper');constgenerator=require('./lib/generator');constpage='https://www.pref.fukui.lg.jp/doc/toukei-jouhou/opendata/list_ct_gomisyusyubi.html';// 「ごみ収集日一覧」ページのURL(async()=>{// ページ内の17市町のCSVデータのURLを取得constresources=awaitscraper.scrape(page)// すべてのCSVを取得してJSONに変換して出力awaitPromise.all(resources.map(resource=>generator.generate(resource)))console.log('できたよ!')})();

絵子「scrapergeneratorっていうのが、樹里が作ったモジュール?」
樹里「そう。scraperで「ごみ収集日一覧」ページからCSVへのリンクを取得している。で、generatorでCSVを取得してJSONに変換している」
絵子「なるほど」
樹里「では、各モジュールの動きをみてみよう」

lib/scraper.js

樹里「次に、ページをスクレイピングして、CSVへのリンクを取得するscraperモジュールだ」

lib/scraper.js
/*
  指定されたページ内の、CSVへのリンクをを取得します。
*/constfetch=require('node-fetch');constcheerio=require('cheerio');consturl=require('url');module.exports.scrape=async(page)=>{// 指定されたページのHTMLを取得するconstresponse=awaitfetch(page)constbody=awaitresponse.text()// cheerioでページをスクレイピングconst$=awaitcheerio.load(body)// 末尾が'.csv'のリンクをすべて取得constrelativePaths=await$('a[href$=".csv"]').map((i,el)=>$(el).attr('href')).get()// 絶対パスに変換constabsolutePaths=awaitrelativePaths.map(path=>url.resolve(page,path))returnabsolutePaths}

樹里「スクレイピングにはcheerioというライブラリを使用している」
絵子「知ってる。jQueryっぽく操作できるやつだよね」
樹里「そう。そのcheerioで、属性セレクターを使って、href属性 が ".csv" で終わるa要素、すなわちCSVへのリンクを取得してだな、その配列を返している」
絵子「なるほど」

lib/generator.js

樹里「最後に、データの変換を行うgeneratorモジュールだ」

lib/generator.js
/*
  指定されたURLのCSVを取得し、文字コードをShift-JISからUTF-8にに変換して出力します。
*/constpath=require('path');constfs=require('fs-extra');constfetch=require('node-fetch');constparse=require('csv-parse/lib/sync');module.exports.generate=async(resource)=>{// ファイル名を生成constfile=path.basename(resource,'.csv')+'.json'// 指定されたURLのCSVを取得constresponse=awaitfetch(resource)constbuffer=awaitresponse.arrayBuffer()// CSVの文字コードをShift-JISからUTF-8にに変換constdecoder=newTextDecoder("Shift_JIS")constcsv=decoder.decode(buffer)// CSVをJSONに変換constjson=awaitparse(csv,{columns:true,trim:true})// JSONを出力constresult=awaitfs.outputJson(path.join('dist',file),json,{spaces:4})returnresult};

樹里「まず、node-fetchでCSVを取得して、Shift-JISからUTF-8に変換する」
絵子「へー、TextDecoderっていうので文字コードを変換できるんだね」
樹里「で、csvというライブラリのcsv-parseという機能を使って、CSVをJSONに変換しているわけだ」
絵子「便利なライブラリだねー」

樹里「さて、処理の結果、このようなJSONが出力される」

[{"行":"あ","音":"あ","町名":"在田町","読み":"あいだ","燃える":"火・金","燃えない":"2・4木","プラスチック製容器包装":"月","カン":"1・3水","ビン":"4水","ペットボトル":"2水","ダンボール":"3水","蛍光灯":"4木","キーワード":"清水","備考":"清水南"},//以下略

絵子「これ、キーが日本語になってるけど問題ないの?」
樹里「ああ、仕様に則った正しいJSONだぞ」
絵子「へー、そうなんだ」
樹里「なにより、Shift-JISのCSVよりははるかに扱いやすい」
絵子「よっぽどキライなんだね」


樹里「……さて、無事にShift-JISのCSVをJSONに変換できた」
絵子「めでたしめでたし、だね」
樹里「いやいや、データの形式を変換しただけで、何も出来上がってないぞ。大事なのは、このデータを使ってどんなアプリを作るかだ」
絵子「そりゃそうだ。さ、次はアプリ制作に挑戦だ!」

Author

8amjp

Mac Nodebrewを用いてNode.jsをインストールした時にエラーが出た話

$
0
0

目的

  • Nodebrewを用いたNode.jsインストール時に出たエラーを解決した話をまとめる

実施環境

  • ハードウェア環境
項目情報備考
OSmacOS Catalina(10.15.3)
ハードウェアMacBook Air (11-inch ,2012)
プロセッサ1.7 GHz デュアルコアIntel Core i5
メモリ8 GB 1600 MHz DDR3
グラフィックスIntel HD Graphics 4000 1536 MB

エラー内容

  • Nodebrewを使用してNode.jsの最新の安定バージョンをインストールしようとした時に下記のエラーが発生した。
  • 実行コマンドをとエラー内容を下記に記載する。

    $nodebrew install-binary stable
    Fetching: https://nodejs.org/dist/v12.16.1/node-v12.16.1-darwin-x64.tar.gz
    Warning: Failed to create the file                                                                                          
    Warning: /Users/ユーザ名/.nodebrew/src/v12.16.1/node-v12.16.1-darwin-x64.tar.gz: 
    Warning: No such file or directory
    
    curl: (23) Failed writing body (0 != 1016)
    download failed: https://nodejs.org/dist/v12.16.1/node-v12.16.1-darwin-x64.tar.gz
    

エラー原因

  • 原因は単純でインストール先のディレクトリがみなさんのPCに存在しないためインストールできないと言われている。

解決方法

  1. 下記コマンドを実行してインストール用のディレクトリを作成する。

    $mkdir ~/.nodebrew/src
    
  2. もう一度問題のコマンドを実行する。

    $nodebrew install-binary stable
    Fetching: https://nodejs.org/dist/v12.16.1/node-v12.16.1-darwin-x64.tar.gz ###################################################################################################################### 100.0%Installed successfully
    
  3. 正常に実行された。

Node.jsを用いて、ORMにSequelize, DBはRDS(MySQL)という構成でApollo Serverを用いて、GraphQL Serverを構成する【勉強メモ】

$
0
0

最初に

これはNode.js環境で, ORMにはSequelize, DBにはMySQLを使った構成で、Apollo Serverを用いてGraphQLサーバを構築してみた際の備忘録となります。

と言っても自身でイチから、これらの構成を構築していったわけではなく、下記のチュートリアルを参照しながらの勉強メモとなります。
(ちょうど同じ構成での例を探していたところ、丁寧に書かれていた下記のドキュメントを見つけました。ありがたい)

How To Set Up a GraphQL Server in Node.js with Apollo Server and Sequelize

ちなみにこのドキュメントの中では、sqlite3を用いているので、そこはこちらでMySQLに置き換えて実践しています。
また細かなところで適宜アレンジを施しています。

大枠自体は変わらないので、この構成(Node.js, Sequelizeなどを Apollo Serverと組み合わせる)に興味ある方は、直接ドキュメントを読まれることをおすすめします。
(というかこのポストを読み進めていく場合は、上の DigitalOceanのチュートリアル記事とセットで読んでいくことをおすすめします)

自身で実際に実装したコードはGithubに置いています。
shinshin86/graphql-recipe-server

Sequelizeを用いたDB関連のセットアップ

まずはDB関連のセットアップから行っていきます。
(ここらへん Apollo Serverというよりは Sequelizeの基本的なセットアップの流れになります)

インストール&初期化

必要なライブラリをインストール

yarn add sequelize sequelize-cli mysql2

Sequelize関連の初期化処理を実施

yarn sequelize init

テーブルの作成

次に必要なmodelとmigrationを作成・実施していきます。

まずはUserテーブルから作成

yarn sequelize model:create --name User --attributes name:string,email:string,password:string

作成した項目は空の入力を許可しないようにするなどの設定を行います。
※ここについては参照先の記述( Step 2 — Creating Models and Migrations )を参照してください。

次にRecipeテーブル

yarn sequelize model:create --name Recipe --attributes title:string,ingredients:text,direction:text

こちらも同じ用にmodelとmigrationの内容を編集していきます。
また、ここで userIdの追加も実施しています。
※ここについても参照先の記述( Step 2 — Creating Models and Migrations )を参照してください。

userId:{allowNull:false,type:Sequelize.INTEGER.UNSIGNED,},

ここにはレシピを作成したユーザIDが格納され、後々レシピを作成したユーザ情報を取得するために使われます。

associateの設定

modelも編集したら、UserとRecipeでそれぞれassociateの設定を行っていきます。

// models/user.jsUser.associate=function(models){User.hasMany(models.Recipe)};
// models/recipe.jsから抜粋Recipe.associate=function(models){Recipe.belongsTo(models.User,{foreignKey:'userId'})};

DBに対する文字コード関連の設定を記述する

また、上記 migrationmodelsにはDBに対する文字コードの設定も忘れないように記述します。
これを忘れると、日本語で入力した場合に文字コード関連でエラーになります。
(実はすっかり忘れていて、日本語を使ってエラーになったりしていました)

migrationファイルの場合、 queryInterface.createTableの第3引数に下記の内容をセットします。

{charset:'utf8',collate:'utf8_general_ci',}

また modelファイルの場合は、sequelize.defineの第3引数に下記の記述をセットします。

{charset:'utf8',collate:'utf8_general_ci',}

migrationの実施

すでにローカルにMySQLは立ち上がっているものとします。

Sequelizeはセットアップしたデフォルトの状態だと password: nullでアクセスするようになっているかと思いますが、流石にそれは現実味がない気がしたので、一応形だけですが、

  • rootというユーザ名、
  • passwordというパスワード

で接続するように config/config.jsonに記述しました。
なので、DB自体もそのような設定で動かしています。
(これも現実味ないといえばないですが...)

ちなみに自身はローカルで動くDocker上に、最新のMySQLを立ち上げて、そちらを使っていきます。

下記のコマンドでDBの作成・migrationを実施していきます

yarn sequelize db:create
yarn sequelize db:migrate

GraphQL Serverを作成する

ここからが本番です。
必要なライブラリをインストールしていきます。

apollo-servergraphqlに依存するため、こちらも併せてインストールしています。
また bcryptjsはユーザのパスワードをハッシュ化するために使用します。

yarn add apollo-server graphql bcryptjs

次に srcディレクトリを作成し、必要なファイルを作成していきます。

mkdir src
nv src/index.js

ソース自体は参照元の Step 3 — Creating the GraphQL Serverを参照してもらうとして、下記の context: { models }でmodels側とのつなぎ込みを行っているようでした。

constserver=newApolloServer({typeDefs,resolvers,context:{models}})

ちなみにGraphQLには Query, Mutations, Subscriptionsがありますが、このチュートリアルではQuery, Mutationsに焦点が当てられています。

schemaを作成していく(GraphQL)

次に src/schema.jsを作成していきます。
記述を見ると、設定したassociateを反映させた構成になっているのが分かります。

typeUser{id:Int!name:String!email:String!recipes:[Recipe!]!}typeRecipe{id:Int!title:String!ingredients:String!direction:String!user:User!}

queryは3つ設定されているようです。

  • user IDを引数にしてユーザ情報を取得するもの
  • すべてのレシピを取得するもの
  • recipe IDを引数にしてレシピ情報を取得するもの
typeQuery{user(id:Int!):UserallRecipes:[Recipe!]!recipe(id:Int!):Recipe}

mutationは2つ設定されています。

  • name, email, passwordを引数にしてユーザを作成するもの
  • userId, title, ingredients, directionを引数にしてレシピを作成するもの
typeMutation{createUser(name:String!,email:String!,password:String!):User!createRecipe(userId:Int!title:String!ingredients:String!direction:String!):Recipe!}

resolverを設定していく(GraphQL)

上に書いたqueryに対応する実際の処理がresolverには書かれています。
実際にどういうロジックが動くのかはこちらを見れば、大体イメージがつくかと思います。
resolver内に実際に書かれるロジックは、特にGraphQL的なものというのはそれほどなく、実際の取得ロジックなどが書かれる形となるので(今回で言えば、Sequelizeを用いたデータ作成・取得処理など)、結構すぐに馴染める印象でした。

例えば MutationのcreateUserの場合ならば、下記のように実装されています。

asynccreateUser(root,{name,email,password},{models}){returnmodels.User.create({name,email,password:awaitbcrypt.hash(password,10),});},

Sequelize v5ではfindByIdではなくfindByPkとなる(余談)

ちなみに現時点で sequelizeの最新のversionをインストールした場合、sequelizeのv5系がインストールされるかと思います。
v5ではsequelizeに実装されていた findByIdは廃止され findByPkに移行しています。
参照しているドキュメントでは findByIdで書かれているので、 ここは findByPkに書き換える必要があります。
(sequelize v4系をインストールした場合は書き換える必要はありません)

diff --git a/src/resolvers.js b/src/resolvers.js
index 7372e74..0cacc9b 100644
--- a/src/resolvers.js
+++ b/src/resolvers.js
@@ -3,13 +3,13 @@ const bcrypt = require('bcryptjs');
 const resolvers = {
   Query: {
     async user(root, { id }, { models }) {
-      return models.User.findById(id);
+      return models.User.findByPk(id);
     },
     async allRecipes(root, args, { models }) {
       return models.Recipe.findAll();
     },
     async recipe(root, { id }, { models }) {
-      return models.Recipe.findById(id);
+      return models.Recipe.findByPk(id);
     },
   },
   Mutation: {

ApolloServerのcontextについて

第3引数として modelsが渡っていますが、これは src/indexでcontextに modelsを指定すると渡せるようです。

constmodels=require('../models');constserver=newApolloServer({typeDefs,resolvers,context:{models},});

例えば下記のようなコードを書いて、該当の箇所のコードを動かすと、 { hoge: 'hogehoge' }がログとして出力されます。

diff --git a/src/index.js b/src/index.js
index e1049b7..133f156 100644
--- a/src/index.js
+++ b/src/index.js
@@ -6,7 +6,7 @@ const models = require('../models');
 const server = new ApolloServer({
   typeDefs,
   resolvers,
-  context: { models },
+  context: { models, hoge: 'hogehoge' },
 });

 server
diff --git a/src/resolvers.js b/src/resolvers.js
index 0cacc9b..3bc1d24 100644
--- a/src/resolvers.js
+++ b/src/resolvers.js
@@ -8,7 +8,8 @@ const resolvers = {
     async allRecipes(root, args, { models }) {
       return models.Recipe.findAll();
     },
-    async recipe(root, { id }, { models }) {
+    async recipe(root, { id }, { models, hoge }) {
+      console.log({hoge})
       return models.Recipe.findByPk(id);
     },
   },

他に書き残しとくべき箇所というのも、あまりないのですが、
下記の user.getRecipes(), recipe.getUser()などは Sequelize側での処理になります。
associateで設定しているゆえに、こういう形で取得ができます。

User:{asyncrecipes(user){returnuser.getRecipes();},},Recipe:{asyncuser(recipe){returnrecipe.getUser();},},

これで、動かすための必要な実装はすべて完了です。

Apollo Playgroundで実際に試してみる

下記コマンドでsevrerを起動します。

node src/index.js
# もしくは "yarn start"

http://localhost:4000/
にアクセスすると、親しみやすいApolloのPlaygroundが表示されます。

とりあえずuserを作成して見ようと思います。

mutation{createUser(name:"テストユーザ1"email:"text@example.com"password:"password"){idnameemail}}

すると下記のような反応が返ってきます。

{"data":{"createUser":{"id":1,"name":"テストユーザ1","email":"text@example.com"}}}

サーバのログを見ると、SQLが発行されているのも確認できます。

Executing(default):INSERTINTO`Users`(`id`,`name`,`email`,`password`,`createdAt`,`updatedAt`)VALUES(DEFAULT,?,?,?,?,?);

次にレシピを作成します。
先ほど作成したテストユーザ1に紐づくレシピを作成します。

mutation{createRecipe(userId:1title:"サンプルレシピ1"ingredients:"Salt, Pepper"direction:"Add salt, Add pepper"){idtitleingredientsdirectionuser{idnameemail}}}

下記のようなレスポンスが返ります。

{"data":{"createRecipe":{"id":1,"title":"サンプルレシピ1","ingredients":"Salt,Pepper","direction":"Addsalt,Addpepper","user":{"id":1,"name":"テストユーザ1","email":"text@example.com"}}}}

サーバのログには下記のようなSQLが発行されているのが確認できます。

INSERTINTO`Recipes`(`id`,`title`,`ingredients`,`direction`,`createdAt`,`updatedAt`,`userId`)VALUES(DEFAULT,?,?,?,?,?,?);

また、同時レスポンス時に必要となるSQLが発行されているのも分かります。

SELECT`id`,`name`,`email`,`password`,`createdAt`,`updatedAt`FROM`Users`AS`User`WHERE`User`.`id`=1;

User作成時は SELECTは発行されていませんでしたが、今回は紐づくユーザ情報も返す必要があるため、SELECTクエリを発行する必要があったということかと想像します
(ソースはまだ読んでいません)

queryについてはあまりここに書かなくても、結構情報はある気がしたので、ざっくりと。

query{allRecipes{idtitleuser{name}}}

ちなみに上のようなqueryを発行した場合、SQL的には下記のように返ってくるようです。

SELECT`id`,`title`,`ingredients`,`direction`,`createdAt`,`updatedAt`,`userId`,`UserId`FROM`Recipes`AS`Recipe`;SELECT`id`,`name`,`email`,`password`,`createdAt`,`updatedAt`FROM`Users`AS`User`WHERE`User`.`id`=1;

テーブルjoinして取得するような動きではありませんが、別にそういうオプションがあるのか、実装的にそういう形になっているのかは今後調べていくこととします。
結果は下記の通り。

{"data":{"allRecipes":[{"id":1,"title":"サンプルレシピ1","user":{"name":"テストユーザ1"}}]}}

ざっくりとではありますが、以上勉強メモとなります。

参照

How To Set Up a GraphQL Server in Node.js with Apollo Server and Sequelize

Model | Sequelize(findByPk)


新型コロナウイルス感染症相談ボットの作成

$
0
0

概要

普段は耳鼻咽喉科の開業医をしています。

新型コロナウイルス感染患者数が増えていますね。発熱や風邪症状が出ると心配になるかと思います。各自治体に「帰国者・接触者相談センターセンター」があり相談の目安が政府から公表されているのは皆さんもご存じかと思います。それとは別に新型コロナウイルス感染症が流行している国や地域に行った方などが発熱や風邪症状が出た場合は医療機関を受診する前にまず「帰国者・接触者相談センター」に連絡することになっています。

このあたりが少しややこしいので『ボットの質問に答えていくと「帰国者・接触者相談センター」に連絡すべきかどうかがわかるLINE Bot」を作成しました。

適切な電話相談のタイミングが分かり、感染の拡大や重症化の防止、相談センターの方の負担軽減につながればいいなと思っています。

完成動画

作成方法

政府や自治体からの新型コロナウイルスに関する発表、所轄の保健所や学会からの連絡を基にプログラムを作成しました。
新型コロナウイルスの感染が認められている国・地域の情報は外務省のホームページに、
国内のクラスターマップは厚生労働省のホームページ(地方自治体の報道発表等に基づき新型コロナウイルス厚生労働省対策本部が集計した速報値に基づくもので、随時更新される)にリンクさせました。
電話相談の基準を満たしているならば連絡先が表示され、そうでない場合は自宅安静やかかりつけ医への相談が推奨されます。
※このボットは「発熱や風邪症状がある方」を対象としています。

こちらのBotのコードをいじって作ったので変数名が一部そのままになってます。
耳年齢を判定するLINE Bot×Iotの作成

index.js
'use strict';require('dotenv').config();constexpress=require('express');constline=require('@line/bot-sdk');constPORT=process.env.PORT||3000;constconfig={channelSecret:"自分のchannelSecret",channelAccessToken:"自分のchannelAccessToken"};constapp=express();app.use(express.static('public'));app.get('/',(req,res)=>res.send('Hello LINE BOT!(GET)'));//ブラウザ確認用(無くても問題ない)app.post('/webhook',line.middleware(config),(req,res)=>{console.log(req.body.events);//ここのif分はdeveloper consoleの"接続確認"用なので削除して問題ないです。if(req.body.events[0].replyToken==='00000000000000000000000000000000'&&req.body.events[1].replyToken==='ffffffffffffffffffffffffffffffff'){res.send('Hello LINE BOT!(POST)');console.log('疎通確認用');return;}Promise.all(req.body.events.map(event=>handleEvent(event,req))).then((result)=>res.json(result));});constclient=newline.Client(config);functionhandleEvent(event,req){// console.log(req);if(event.type!=='message'||event.message.type!=='text'){returnPromise.resolve(null);}// LINE botのプログラムletans="";letquestion=event.message.text;lethz;letyes="";letno="";if(question=="開始"){hz=1;ans="発熱または風邪症状がありますか?";yes="発熱:はい";no="発熱:いいえ";}elseif(question=="発熱:はい"){hz=2;ans="新型コロナウイルス感染症であることが確定した人と濃厚接触歴がありますか?";yes="感染者濃厚接触:はい";no="感染者濃厚接触:いいえ";}elseif(question=="感染者濃厚接触:いいえ"){hz=3;ans="発症前14日以内に新型コロナウイルス感染症の流行が確認されている国や地域に行きましたか?";yes="流行地域:はい";no="流行地域:いいえ";}elseif(question=="流行地域:いいえ"){hz=4;ans="発症前14日以内に新型コロナウイルス感染症の流行が確認されている国や地域に行った人と濃厚接触歴がありますか?";yes="流行地域、濃厚接触:はい";no="流行地域、濃厚接触:いいえ";}elseif(question=="流行地域、濃厚接触:いいえ"){hz=5;ans="発症前14日以内にライブハウス、スポーツクラブ、介護施設、老人ホーム、お祭り、クルーズ船など感染者が多発した施設あるいはイベントに行きましたか?";yes="施設、イベント:はい";no="施設、イベント:いいえ";}elseif(question=="施設、イベント:いいえ"){hz=4;ans="発症前14日以内に感染者が多発した施設あるいはイベントに行った人と濃厚接触歴がありますか?";yes="施設、濃厚接触:はい";no="施設、濃厚接触:いいえ";}elseif(question=="施設、濃厚接触:いいえ"){ans="以下の(1)または(2)の症状が2日以上続いていますか?(1)風邪の症状や37.5度以上の発熱(解熱剤を飲み続けなければならない場合も同様)、(2)強いだるさや息苦しさ";yes="2日以上:はい";no="2日以上:いいえ";}elseif(question=="2日以上:はい"){ans="以下のいずれかに当てはまりますか?高齢である、糖尿病・心不全・呼吸器疾患(COPD等)の基礎疾患がある、透析を受けている、免疫抑制剤や抗がん剤等を用いている、妊娠中である";yes="基礎疾患:はい";no="基礎疾患:いいえ";}elseif(question=="基礎疾患:いいえ"){ans="以下の(1)または(2)の症状が4日以上続いていますか?(1)風邪の症状や37.5度以上の発熱(解熱剤を飲み続けなければならない場合も同様)、(2)強いだるさや息苦しさ";yes="4日以上:はい";no="4日以上:いいえ";}elseif(question=="発熱:いいえ"||question=="2日以上:いいえ"||question=="4日以上:いいえ"){hz=0;ans="自宅で安静にするか、かかりつけ医にご相談ください。";}elseif(question=="感染者濃厚接触:はい"||question=="流行地域:はい"||question=="流行地域濃厚接触:はい"||question=="流行地域、濃厚接触:はい"||question=="施設、イベント:はい"||question=="施設、濃厚接触:はい"){hz=6;ans="医療機関は受診せず、「船橋市新型コロナウイルス感染症相談センター(電話:047-409-3127)【聴覚障害などにより電話での相談が難しい方は、FAX:047-409-2952】」に連絡してください。";}elseif(question=="基礎疾患:はい"||question=="4日以上:はい"){hz=7;ans="「船橋市新型コロナウイルス感染症相談センター(電話:047-409-3127)【聴覚障害などにより電話での相談が難しい方は、FAX:047-409-2952】」に相談してください。";}elseif(question=="電話"){hz=7;ans="「船橋市新型コロナウイルス感染症相談センター(電話:047-409-3127)【聴覚障害などにより電話での相談が難しい方は、FAX:047-409-2952】」に相談してください。";}lettitle;leturl;if(hz==1){url="「はい」か「いいえ」どちらかをお選びください";}elseif(hz==2){url="※濃厚接触とは、以下のような状況です : 感染者と同居、車内や航空機内等で、2メートル以内での長い時間の会話 / マスクや手袋などの個人防護具なしでの感染者の看護・介護 / 感染者の唾や鼻水、体液等に直接触れた";}elseif(hz==3){title="流行国・地域はこちら"url="https://www.anzen.mofa.go.jp/covid19/country_count.html";}elseif(hz==4){url="※濃厚接触とは、以下のような状況です : 同居、車内や航空機内等で、2メートル以内での長い時間の会話 / マスクや手袋などの個人防護具なしで看護・介護 / 唾や鼻水、体液等に直接触れた";}elseif(hz==5){title="クラスターマップはこちら"url="https://www.mhlw.go.jp/content/10900000/000609647.pdf";}elseif(hz==6||hz==7){title="全国の相談センターはこちら"url="https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/kenkou_iryou/covid19-kikokusyasessyokusya.html";}if(hz==0){returnclient.replyMessage(event.replyToken,{type:'text',text:ans});}if(hz==1||hz==2||hz==4){returnclient.replyMessage(event.replyToken,[{"type":"template","altText":"this is a confirm template","template":{"type":"confirm","text":ans,"actions":[{"type":"message","label":"はい","text":yes},{"type":"message","label":"いいえ","text":no}]}},{type:"flex",altText:"追加情報",contents:{type:"bubble",body:{type:"box",layout:"vertical",spacing:"md",contents:[{type:"text",text:url,wrap:true,color:"#aaaaaa",size:"lg"}]}}}]);}if(hz==3||hz==5){returnclient.replyMessage(event.replyToken,[{"type":"template","altText":"this is a confirm template","template":{"type":"confirm","text":ans,"actions":[{"type":"message","label":"はい","text":yes},{"type":"message","label":"いいえ","text":no}]}},{type:"flex",altText:"Flex Message",contents:{type:"bubble",footer:{type:"box",layout:"vertical",spacing:"sm",contents:[{type:"button",action:{type:"uri",label:title,uri:url},height:"sm",style:"link"}]}}}]);}if(hz==6||hz==7){console.log("+++++++++++++電話+++++++++++")returnclient.replyMessage(event.replyToken,[{type:'text',text:ans},{type:"flex",altText:"Flex Message",contents:{type:"bubble",footer:{type:"box",layout:"vertical",spacing:"sm",contents:[{type:"button",action:{type:"uri",label:title,uri:url},height:"sm",style:"link"}]}}}]);}else{returnclient.replyMessage(event.replyToken,[{"type":"template","altText":"this is a confirm template","template":{"type":"confirm","text":ans,"actions":[{"type":"message","label":"はい","text":yes},{"type":"message","label":"いいえ","text":no}]}},]);}}(process.env.NOW_REGION)?module.exports=app:app.listen(PORT);console.log(`Server running at ${PORT}`);

考察

現在、連絡先の電話やFaxの番号は医院がある自治体(船橋市)の「帰国者・接触者相談センターセンター」のものになっています。船橋市在住でない方は電話しないようお願いいたします。他の地域のユーザーのため全国の相談センターが出ている厚生労働省のホームページをリンクしていますが、ユーザーの位置情報や自宅住所を入力するとユーザー居住地の「帰国者・接触者相談センター」の電話番号などが分かるようにできれば他の自治体の方も使いやすいものができるのではないかと思っています。やり方ご存じの方は教えていただけると嬉しいです。

ボットのURLとQRコード

URLhttps://lin.ee/teqrODx

QRコード
covid19.png

位置情報を送ると最寄りのラーメン店を教えてくれるLINE botをつくってみた🍜

$
0
0

概要

 ProtoOut Studioの活動の一環で、LINE botに位置情報を送ると、その近辺のラーメン屋さんを教えてくれるbotを作りました🍜!ProtoOuto Studioについてはこちらをご参照ください。

【デモ】

 本記事ではこのLINE botのサーバプログラムと、ラーメン店情報を検索するためにぐるなび APIを解説しています。基礎的な機能のみ実装しているので、店舗の星の多さ、複数件表示などは未実装です。

 位置情報を送ると、その最寄りのラーメン屋さんを一軒返すところまで動かしました。
以下、2020年3月29日時点の情報です。

開発環境

OS:Windows 10
Node.js:v10.15.3

【ライブラリバージョン】
@line/bot-sdk:6.8.4
express:4.17.1
axios:0.19.2

構成

 構成は次のようになっています。ローカルPC上でNode.jsを動かしているので、グローバルネットワークとのつながりをngrokでトンネリングしています。

構成図.jpg

 位置情報をNode.jsサーバが受け取ると、ぐるなび APIを利用して最寄りののラーメン店情報を取得します。このとき、ユーザから送られた位置情報をぐるなび APIのリクエストURLに含めています。

実装

ぐるなび APIの調査

 ぐるなび APIはAPIの使用説明だけでなく、APIテストツールまで用意されていました。手始めに、freewordクエリを追加してリクエストしてみると、レスポンスが下の方に表示されます。
(アクセスキーはテスト用になっています)

image.png

 どんなクエリがあるかは、API仕様のレストラン検索 APIで公開されています。

プログラムからアクセスしてみる

 LINE botとのやり取りと、APIアクセスはこちらのソースコードをもとに進めていきます。
APIテストツールを使うと、リクエストURLが生成されるのでコピーしてaxisos.getに引数に与えます。
こんな感じです。

axios.get('https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=b17d2f36873123b0d0f09e9139556c79&freeword=ラーメン');

 この状態でアクセスしたら、次のようなエラーが発生しました。

Request path contains unescaped characters

 コーディングミスというよりは、URLとして認識されていないようなエラーメッセージですね。試しにフリーワードをローマ字(ra-men)にしたらエラーが解消されて、レスポンスが返るようになりました!
↓レスポンスのログ

ローマ字なら動いた.JPG

 一先ず、これでレスポンスが返るので先に進みます。日本語対応は後述の「後回しにしていた日本語対応」で解説しています。

最寄りの店に絞る

 フリーワード検索のみだと全国の店が検索されてしまうので、最寄りの店に絞ります。これはぐるなび APIのクエリに経緯を追加することで絞ることが可能です。

 最初は経緯を固定で動かします。経緯を調べるにはGoogleマップが便利です。今回はProtoOut Studioの本拠地であるgranicaにしてみました。

【リクエストURL」

https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=アクセスキー&latitude=35.704607&longitude=139.772416&range=2&freeword=ラーメン

 このURLで問題なくレスポンスが来ればOKです。

が、居酒屋が引っかかる!!!!!!
image.png

ラーメン店に絞る

 ラーメンに絞りたいので、レスポンスデータの中のcategoryでフィルタリングしました。

for(varnum=0;num<=response.data.rest.length;num++){if(response.data.rest[num].category==='ラーメン'){console.log(response.data.rest[num]);ramen_url=response.data.rest[num].url_mobile;break;}}

 これで最寄りのラーメン店に絞ることができました!と、思いきや最寄りにラーメン店が見つからなかった場合、エラーが発生します。ちなみに、最寄りとは半径500m圏内です。今回は正常系のみ作ることを目的とし、エラーハンドリングをスルーします...。

後回しにしていた日本語対応

 フリーワードに日本語が入っていることが原因なので、URLにエンコードしてくれるencodeURI関数がありました。こちらの記事の通りになおすと、フリーワードに日本語が入っていても通るようになりました!
こんなコードです。

url='https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=アクセスキー&latitude=35.704607&longitude=139.772416&range=2&freeword=ラーメン';constencodeUrl=encodeURI(url);constresponse=awaitaxios.get(encodeUrl);

LINE botへのレスポンスを位置情報にする

 このままテキストで返してもよいのですが、LINE botには位置情報を返す機能がありまので、位置情報で返してみました。ちなみに、テキストでURLを返すと次のようになります。
Screenshot_20200328-230452_LINE.jpg

これを位置情報にすると、

Screenshot_20200328-231744_LINE.jpg

こっちの方が見栄え良さそうですね イェーイ(/・ω・)/

LINE botで位置情報を返すコードは次の通りです。経緯だけではなく住所も返す必要があります。
コード中のhitnumは、レスポンスデータの中で、category”ラーメン”にヒットした位置が格納されているとします。ぐるなび APIの良いところはこれらの情報が全てそろっていることです👍

returnclient.replyMessage(event.replyToken,{type:'location',title:response.data.rest[hitnum].name,address:response.data.rest[hitnum].address,latitude:response.data.rest[hitnum].latitude,longitude:response.data.rest[hitnum].longitude});

位置情報入力を追加

 最後に位置情報入力に対応させます。LINEから位置情報を受け取ってログに出し、URLに加えるコードは次の通りです。入力が位置情報のみとなるようにtypeで判定しています。

 if(event.type!=='message'||event.message.type!=='location'){returnPromise.resolve(null);}console.log(event.message.latitude+' : '+event.message.longitude); url='https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=アクセスキー&latitude='+event.message.latitude+'&longitude='+event.message.longitude+'&range=2&freeword=ラーメン';

余談

 
 今回、正常系で動くところまで作れたのですが、ラーメン店が見つからないかった場合のエラーハンドリングを入れたかったなと思います。例えば、かわいい動物画像を出すとか。

 もう一つ思ったのは、jsonデータのコンソールログデバッグは時間がかかったなと。APIの解説がされているサイトをみて一気にコーディングできたらよいのですが...。まずは経験して慣れることが大切ですね。

 ちなみに、ProtoOut Studioの授業後から制作を開始し、Qiita公開まで6時間程度かかりました。
javascriptのデバッグ不慣れなのと、Qiita記事執筆をもう少し効率化できそうなので、もう少し頑張ってプロトアウトのサイクルを短くしてきたいなと思っています。

 ほんとに余談ですが、ProtoOut Studioの一環で進めているので、よくわからないエラーが発生して困っていると講師の方々に相談できます。校長である菅原のびすけさんに直接コーディング指南していただいてものすごく緊張していました(;'∀')

 今回はぐるなびAPIを利用しましたが、他にも猫の種類検索APIこの猫なに猫?Harry Potter APIなど気になるAPIが沢山あります(^^♪

 今後はこのLINE botをベースに、connpass APIやGoogle MAP APIなどと連携して、勉強会やイベントのお知らせと夕食を提案してくれるようなサービスにしていけたら面白そうかなと思っています。

参考

ソースコード

'use strict';constaxios=require('axios');constexpress=require('express');constline=require('@line/bot-sdk');constPORT=process.env.PORT||3000;constconfig={channelSecret:'LINE botのチャンネルシークレット',channelAccessToken:'LINE botのアクセストークン'};constapp=express();app.get('/',(req,res)=>res.send('Hello LINE BOT!(GET)'));//ブラウザ確認用(無くても問題ない)app.post('/webhook',line.middleware(config),(req,res)=>{console.log(req.body.events);//ここのif文はdeveloper consoleの"接続確認"用なので後で削除して問題ないです。if(req.body.events[0].replyToken==='00000000000000000000000000000000'&&req.body.events[1].replyToken==='ffffffffffffffffffffffffffffffff'){res.send('Hello LINE BOT!(POST)');console.log('疎通確認用');return;}Promise.all(req.body.events.map(handleEvent)).then((result)=>res.json(result));});constclient=newline.Client(config);asyncfunctionhandleEvent(event){varurlvarramen_url;varhitnum;// 位置情報のみに入力制限if(event.type!=='message'||event.message.type!=='location'){returnPromise.resolve(null);}// 取得した位置情報をログに表示console.log(event.message.latitude+' : '+event.message.longitude);// ぐるなびAPIを使うためのURLに経緯を加えるurl='https://api.gnavi.co.j
p/RestSearchAPI/v3/?keyid=af2b4862cbe801c5e2e1b87ef52881f6&latitude='+event.message.latitude+'&longitude='+event.message.longitude+'&range=2&freeword=ラーメン';constencodeUrl=encodeURI(url);// ぐるなびAPIに問い合わせconstresponse=awaitaxios.get(encodeUrl);//レスポンスの中からcategory"ラーメン"を探索for(varnum=0;num<=response.data.rest.length;num++){if(response.data.rest[num].category==='ラーメン'){//      console.log(response.data.rest[num]);hitnum=num;ramen_url=response.data.rest[num].url_mobile;break;}}// ヒットしたラーメン店の住所をLINE botに返すreturnclient.replyMessage(event.replyToken,{type:'location',title:response.data.rest[hitnum].name,address:response.data.rest[hitnum].address,latitude:response.data.rest[hitnum].latitude,longitude:response.data.rest[hitnum].longitude});}app.listen(PORT);console.log(`Server running at ${PORT}`);

npmでReactのプロジェクト作成

$
0
0
npx create-react-app プロジェクト名

プロジェクト作成すると下記画面が表示される

Success! Created react-app at /Users/xxx/Myapp/React/learning/react-app
Inside that directory, you can run several commands:

  npm start
    Starts the development server.

  npm run build
    Bundles the app into static files for production.

  npm test
    Starts the test runner.

  npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!

We suggest that you begin by typing:

  cd react-app
  npm start

上記の画面にはコマンド毎の操作説明が表示されており、こちらのコマンドはnpmの他にyarnでも実行可能

1.yarn start又は npm start
・webブラウザを起動
2.yarn build又は npm run build
・プロジェクトのビルド(プロジェクトのファイルから実際のWebサーバーにアップロードして利用するファイル類を生成する)
3.yarn test又は npm test
・テストプログラムを実行して、アプリケーションのテストを行う
4.yarn eject又は npm run eject
・プロジェクトのインジェクトを行う

【JS】RSSで取得した記事を日付順にし、表示形式を変更する(Javascript・node.js)

$
0
0

解決する問題

RSSで取得した記事を、日付順にして日付の表示形式を変更する。

今回はRSSでコロナウイルスに関しての記事を取得しました。

対象読者

・node.jsでxmlを取得する事ができる方。
・express-generatorを触った事がある方。
・xmlの表示形式の知識がある方。

express-generatorを使ってXMLを取得しているところから進めていきます。

環境

OS: macOS
Node.js: v13.5.0
npm: 6.14.3
express: ~4.16.1
ejs: ~2.6.1,

RSSで記事を取得した時の状況

記事を取得し表示させると日付順にならず、見づらい

hello.js↓

router.get('/',(req,res,next)=>{varopt={host:'news.google.com',port:443,path:'/rss/search?q=corona&q=korona&hl=ja&gl=JP&ceid=JP:ja'};http.get(opt,(res2)=>{varbody='';res2.on('data',(data)=>{body+=data;});res2.on('end',()=>{parseString(body.trim(),(err,result)=>{vardata={title:'コロナウイルスの最新情報を表示します',content:result.rss.channel[0].item};res.render('hello',data);})});});});

hello.ejs↓

<!DOCTYPE html><html><head><metahttp-equiv="content-type"content="text/html; charset=UTF-8"><title><%=title%></title><linkrel='stylesheet'href="/stylesheets/style.css"/></head><body><header><h1><%=title%></h1></header><divrole="main"><%if(content!=null){%><ol><%for(variincontent){%><%varobj = content[i];%><li><%=obj.pubDate%><ahref="<%=obj.link %>"><%=obj.title%></a></li></tr><%}%></ol><%}%></div></body></html>

スクリーンショット 2020-03-29 15.55.27.png

(今回取得したxml
https://news.google.com/rss/search?q=corona&q=korona&hl=ja&gl=JP&ceid=JP:ja)

解決策

①xmlの記事の中のitemを配列に入れていく。

for in を使ってxmlのitemを配列に入れる処理をループさせます。

配列を作る、ループを作る、配列へpushという順番です。

※ソートする為に配列へ入れます。

<!--配列を作成--><%varhash=newArray%><!--xmlitemをループ処理する--><%for(variincontent){%><%varobj=content[i];%><!--itemを配列へ追加--><%hash.push(obj);%><%}%>

※ejsの中にjsを書いています。
※content = result.rss.channel[0].item

②配列をソートして日付順に並べる

<!--配列をソートして日付順に変更--><%hash.sort(function(a,b){return(a.pubDate<b.pubDate?1:-1);});%>

これで配列の中のitemが、xmlのpubDateの日付順に並びました。
※こちらもejsの中にjsを書いています。
※参考にした記事は下に載っています。

③日付の表示形式を変更

1、配列をfor inでループさせる
2、ループの中にDateオブジェクトを作成
3、日付の形式を変更
4、(西暦2020年を削除)任意
5、ループ処理の中で記事を表示する

<!--配列をループ処理--><%for(variinhash){%><%varobj2=hash[i]%><!--日付の表示形式を変更--><%vardate2=newDate(obj2.pubDate);varb=date2.toLocaleString('ja-JP',{era:'long'});obj2.pubDate=b;%><!--西暦を削除--><%varobj3_pubDate=obj2.pubDate.replace('西暦2020年','');%><!--表示--><divclass="center"><ul><li><ahref="<%=obj2.link %>"><divclass="Date"><%=obj3_pubDate%></div>
<divclass="title"><%=""+obj2.title%></div>
</a>
</li>
</ul>
</div>
<%}%>

表示結果

css追加前↓
スクリーンショット 2020-03-29 17.25.04.png

css追加後↓
スクリーンショット 2020-03-29 17.26.40.png

変更後のコード

hello.ejs↓

<!DOCTYPE html><htmllang="ja"><head><metacharset="UTF-8"><metahttp-equiv="content-type"content="text/html; charset=UTF-8"><title><%=title%></title><linkrel='stylesheet'href="/stylesheets/style.css"/></head><divclass="style"><!-- 更新日時を日本語へ変更する --><%varupdate2 = newDate(update);varupdate3 = update2.toLocaleString('ja-JP',{era:'long'});update = update3;%><!-- 更新日時の西暦を消す --><%varupdate4 = update.replace('西暦2020年','');%></div><body><header><h1><%=title%>更新(<%=update4%>)</h1></header><divrole="main"><%if(content!=null){%><!-- 配列を作成 --><%varhash = newArray%><!-- xmlのitemをループ処理する --><%for(variincontent){%><%varobj = content[i];%><!-- itemを配列へ追加 --><%hash.push(obj);%><%}%><!-- 配列をソートして日付順に変更 --><%hash.sort(function(a,b){return(a.pubDate<b.pubDate?1:-1);});%><!-- 配列をループ処理 --><%for(variinhash){%><%varobj2 = hash[i]%><!-- 日付の表示形式を変更 --><%vardate2 = newDate(obj2.pubDate);varb = date2.toLocaleString('ja-JP',{era:'long'});obj2.pubDate = b;%><!-- 西暦を削除 --><%varobj3_pubDate = obj2.pubDate.replace('西暦2020年','');%><!-- 表示 --><divclass="center"><ul><li><ahref="<%=obj2.link %>"><divclass="Date"><%=obj3_pubDate%></div><divclass="title"><%=""+obj2.title%></div></a></li></ul></div><%}%><%}%></div></body></html>

hello.js↓

varexpress=require('express');varrouter=express.Router();varhttp=require('https');varparseString=require('xml2js').parseString;router.get('/',(req,res,next)=>{varopt={host:'news.google.com',port:443,path:'/rss/search?q=corona&q=Coronavirus&hl=ja&gl=JP&ceid=JP:ja'};http.get(opt,(res2)=>{varbody='';res2.on('data',(data)=>{body+=data;});res2.on('end',()=>{parseString(body.trim(),(err,result)=>{vardata={title:'コロナウイルスの最新情報を表示します',content:result.rss.channel[0].item,update:result.rss.channel[0].lastBuildDate};res.render('hello',data);})});});});module.exports=router;

参考

配列を日付順にソートする方法
https://infoteck-life.com/a0107-js-array-sort-date/
https://www.p-nt.com/technicblog/archives/58

Dateオブジェクトの使い方入門
https://www.sejuku.net/blog/30171

Dateオブジェクトのプロパティ(日付の表示形式を参考にしました。)
https://so-zou.jp/web-app/tech/programming/javascript/grammar/object/date.htm

ループ処理(今回はfor inでループしています。)
https://qiita.com/endam/items/808a084859e3a101ab8f

文字列から指定した文字を削除する(日付の西暦2020年を削除する為に参考にしました。)
https://zukucode.com/2017/04/javascript-string-remove.html

Catalinaのバージョンアップしたらrails sできなくなったけど、Node.jsのインストールで解決!

$
0
0

筆者の環境

macOS Catalina バージョン 10.15.4
使用言語:Ruby、JavaScript

エラー内容

不注意により、macOSがCatalina バージョン10.15.4に上がってしまった。

それから実装中のアプリでrails sすると、以下のエラーメッセージが表示されサーバーが起動しなくなった。

Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

これで解決!

Node.jsをインストール

左側の12.16.1の方はインストールしても開けず、
右側(最新版)をインストールしたらrails s成功しました!

スクリーンショット 2020-03-29 19.12.24.png

番外編

他にも対処法はいくつかあり、therubyracerというGemのインストールでも解決できるようです。(参考リンクご参照ください)

現在、チーム開発中だったので、自分以外の複数端末への影響を考え今回はGem以外の方法を選択しました。

参考

にさせていただきました。ありがとうございます。
https://qiita.com/azusanakano/items/771dc9919f347de061d7

Viewing all 8808 articles
Browse latest View live