20190716のNode.jsに関する記事は7件です。

Electron を Custom URL Scheme で起動する

やりたいこと

Custom URL Scheme から Electron を起動したい、値も渡したい

例えばブラウザで、 itmss://music.apple.com/jp/album/ignition-single/1378858551 にアクセスすると iTunes が起動し、特定のページに遷移する

これと同じことを実現したい

前提

  • Electron version v5.0
  • electron-builder v20.40.2

手順

Mac

package.json の build に以下を追記する

"build": {
    ...
    "protocols": {
      "name": "myApp IM URL",
      "schemes": [
        "my-appname"
      ]
    },
   ...
}

ビルド後に .dmg イメージからアプリケーションを Mac にインストールすることで、 URL Scheme から Electron を起動することができる

Windows

package.json の build に以下を追記する

"build": {
    ...
    "nsis": {
      "include": "build/installer.nsh",
      "perMachine": true
    },
   ...
}

build/installer.nsh ファイルを追加する

!macro customHeader
    !system "echo '' > ${BUILD_RESOURCES_DIR}/customHeader"
!macroend

!macro preInit
    ; This macro is inserted at the beginning of the NSIS .OnInit callback
    !system "echo '' > ${BUILD_RESOURCES_DIR}/preInit"
!macroend

!macro customInit
    !system "echo '' > ${BUILD_RESOURCES_DIR}/customInit"
!macroend

!macro customInstall
    !system "echo '' > ${BUILD_RESOURCES_DIR}/customInstall"

    DetailPrint "Register My AppName URI Handler"
    DeleteRegKey HKCR "My AppName"
    WriteRegStr HKCR "My AppName" "" "URL:My AppName"
    WriteRegStr HKCR "My AppName" "URL Protocol" ""
    WriteRegStr HKCR "My AppName" "EveHQ NG SSO authentication Protocol" ""
    WriteRegStr HKCR "My AppName\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME}"
    WriteRegStr HKCR "My AppName\shell" "" ""
    WriteRegStr HKCR "My AppName\shell\Open" "" ""
    WriteRegStr HKCR "My AppName\shell\Open\command" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME} %1"
!macroend

!macro customInstallMode
    # set $isForceMachineInstall or $isForceCurrentInstall
    # to enforce one or the other modes.
!macroend

ビルド後、 Setup ファイルからインストールすることで、 URL Scheme から Electron を起動することができる

Custom URI Scheme を Electron 側で取得する

メインプロセス

Mac OS と Windows で書き方が違う

  // for Mac OS
  app.on('open-url', (e, url) => {
    // URL Scheme から開いたときにここが実行される
    webContents.send('customUri', url);
  });

  // アプリの二重起動を防ぐ(for windows)
  const gotTheLock = app.requestSingleInstanceLock();
  if (!gotTheLock) { // すでにウィンドウを開いていた場合、新しい window は quit
    app.quit();
  } else {
    // 2つめのウィンドウが開かれた時のイベントを定義する
    app.on('second-instance', (event, commandLine, workingDirectory) => {
      // mainWindow.webContents.send('log', 'second instance!!');

      commandLine.forEach(cmd => {
        // URIスキームのみを探して、レンダラプロセスに送る
        if (/my-appname:\/\//.test(cmd)) {
          mainWindow.webContents.send('customUri', cmd);
        }
      });

      // すでにメインウィンドウがある場合、それにフォーカスする
      if (mainWindow) {
        if (mainWindow.isMinimized()) { // 最小化してた場合
          mainWindow.restore(); // restore
        }
        mainWindow.focus(); // フォーカス
      }
    });
  }

レンダラプロセス

/**
 * custom uri をメインプロセスから受け取る
 */
ipcRenderer.on('customUri', (event, uri) => {
  console.log('customUri:', uri);
});

参考

http://chords.hatenablog.com/entry/2016/02/22/Electron%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0URI%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B

https://electronjs.org/docs/all#apprequestsingleinstancelock

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

Slackメッセージ 10000 件制限対応: 古いメッセージを一括で削除する

Slackのフリープランで10000件制限をやりくりする

Slackはフリープランだと、10000件しかメッセージを保存できません。
古いものが見えなくなっても困らないけど、中には残しておきたいメッセージもありますよね。
そこで、スター付きのメッセージと、ピン留めしたメッセージは、残して置けるようにしました。

目次

  1. 結論
  2. 手順
    • 2-1. 実行環境を用意
    • 2-2. ソースをダウンロード
    • 2-3. あなたのSlackチームへのアクセス情報を設定
    • 2-4. (オプション) プロキシの設定
    • 2-5. 実行

1. 結論

最古の1000件を削除するプログラムを定期的に実行する

プログラムは、JavaScriptで書く
実行は、コマンドプロンプトから、Node.jsで行う

2. 手順

2-1. 実行環境を用意

Node.jsをインストール
下図の中央左のボタンをクリックしてダウンロード
image.png
全部デフォルト選択でインストール

2-2. ソースをダウンロード

Gitをインストールしている人は、以下のコマンドを実行
git clone https://github.com/teraoka-k/SlackWebAPI-deleteOldChat.git
Gitをインストールしていない人は、ここからzip形式でダウンロードできます
image.png

2-3. あなたのSlackチームへのアクセス情報を設定

ここからSlackのトークンを発行
緑色の「Create token」ボタンを押す
create token.png

※Slack Teamの管理者権限のユーザが望ましい(閲覧権限のあるメッセージしか削除できないため)
 間違って普通のユーザで、トークンを発行してしまっても、
 「Re-issue token」ボタンを押せば、何度でもトークンを発行できるので大丈夫

トークンが発行されたら、全選択して、コピーする
(※上図のxoxp-68094...部分がトークンです)
2-2.でダウンロードしたソースの、deleteOldMsgButPinnedOrStarred.jsをお好きなエディターで開く
下記Stringの値を先ほどコピーしたトークンで置き換え

deleteOldMsgButPinnedOrStarred.js
const token = 'paste your token here';

image.png

2-4. (オプション) プロキシの設定

仕事先だと、プロキシを設定する必要あり
Chromeを立ち上げて、右上の三点リーダから設定を開く
proxyと検索ボックスに入力して、Open proxy setting をクリック
image.png
LANの設定をクリックすると、アドレスとポートが見れるので、それぞれコピーする
以下のコメントを解除

deleteOldMsgButPinnedOrStarred.js
// const proxiedRequest = request.defaults({'proxy': 'http://${your-address}:${your-port-number}'});

先ほどコピーしたアドレスとポートを設定

deleteOldMsgButPinnedOrStarred.js
const proxiedRequest = request.defaults({'proxy': 'http://your-corp-address:8080'});

deleteOldMsgButPinnedOrStarred.jsを保存して閉じる

2-5. 実行

deleteOldMsgButPinnedOrStarred.jsがあるディレクトリで、コマンドプロンプトを開く
下記コマンドを実行
node deleteOldMsgButPinnedOrStarred.js
削除対象のチャット一覧が出力される
削除してよければ、下記のコメントアウトを解除して、再度実行すれば削除される

deleteOldMsgButPinnedOrStarred.js
/** delete chat */
        // top1000OldestChatList.forEach(chat => 
        //     deleteChat(chat.channel, chat.ts).then(msg => 
        //         console.log(msg)
        //     )
        // );

備考

Node.jsは、プロキシ環境下で動かないので、以下の設定が、追加で必要かもです
コマンドプロンプトで下記コマンド実行

cmd for proxy setting of npm
call npm -g config set proxy http://your-corp-address.co.jp:8080
call npm -g config set https-proxy http://your-corp-address.co.jp:8080
call npm -g config set registry https://registry.npmjs.org/
call npm config list

※なお上記コマンドの2行目と3行目は、各自のプロキシのアドレスとポートに置き換えてください
 4行目は固定です(ただしhttpsかhttpかは、Node.jsのバージョンによって替わったことがあります)

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

Slack10000 件制限: スター&ピンどめ以外1000件削除

Slackのフリープランで10000件制限をやりくりする

Slackはフリープランだと、10000件しかメッセージを保存できません。
古いものが見えなくなっても困らないけど、中には残しておきたいメッセージもありますよね。
そこで、スター付きのメッセージと、ピン留めしたメッセージは、残しておけるようにしました。

目次

  1. 結論
  2. 手順
    • 2-1. 実行環境を用意
    • 2-2. ソースをダウンロード
    • 2-3. あなたのSlackチームへのアクセス情報を設定
    • 2-4. (オプション) プロキシの設定
    • 2-5. 実行

1. 結論

最古の1000件(スター&ピンどめ以外)を削除するプログラムを定期的に実行する

プログラムは、JavaScriptで書く
実行は、コマンドプロンプトから、Node.jsで行う

2. 手順

2-1. 実行環境を用意

Node.jsをインストール
下図の中央左のボタンをクリックしてダウンロード
image.png
全部デフォルト選択でインストール

2-2. ソースをダウンロード

Gitをインストールしている人は、以下のコマンドを実行
git clone https://github.com/teraoka-k/SlackWebAPI-deleteOldChat.git
Gitをインストールしていない人は、ここからzip形式でダウンロードできます
image.png

2-3. あなたのSlackチームへのアクセス情報を設定

ここからSlackのトークンを発行
緑色の「Create token」ボタンを押す
create token.png

※Slack Teamの管理者権限のユーザが望ましい(閲覧権限のあるメッセージしか削除できないため)
 間違って普通のユーザで、トークンを発行してしまっても、
 「Re-issue token」ボタンを押せば、何度でもトークンを発行できるので大丈夫

トークンが発行されたら、全選択して、コピーする
(※上図のxoxp-68094...部分がトークンです)
2-2.でダウンロードしたソースの、deleteOldMsgButPinnedOrStarred.jsをお好きなエディターで開く
下記Stringの値を先ほどコピーしたトークンで置き換え

deleteOldMsgButPinnedOrStarred.js
const token = 'paste your token here';

2-4. (オプション) プロキシの設定

仕事先だと、プロキシを設定する必要あり

Chromeを立ち上げて、右上の三点リーダから設定を開く
proxyと検索ボックスに入力して、Open proxy setting をクリック
image.png
LANの設定をクリックすると、アドレスとポートが見れるので、それぞれコピーする
以下のコメントを解除

deleteOldMsgButPinnedOrStarred.js
// const proxiedRequest = request.defaults({'proxy': 'http://${your-address}:${your-port-number}'});

先ほどコピーしたアドレスとポートを設定

deleteOldMsgButPinnedOrStarred.js
const proxiedRequest = request.defaults({'proxy': 'http://your-corp-address:8080'});

deleteOldMsgButPinnedOrStarred.jsを保存して閉じる

2-5. 実行

deleteOldMsgButPinnedOrStarred.jsがあるディレクトリで、コマンドプロンプトを開く
下記コマンドを実行
node deleteOldMsgButPinnedOrStarred.js
削除対象のチャット一覧が出力される(その間およそ1秒!)
image.png
image.png
削除してよければ、y & enter
image.png

備考

Node.jsのパッケージマネージャーnpmは、プロキシ環境下で動かないので、以下の設定が、追加で必要かもです
コマンドプロンプトで下記コマンド実行

cmd for proxy setting of npm
call npm -g config set proxy http://your-corp-address.co.jp:8080
call npm -g config set https-proxy http://your-corp-address.co.jp:8080
call npm -g config set registry https://registry.npmjs.org/
call npm config list

※なお上記コマンドの2行目と3行目は、各自のプロキシのアドレスとポートに置き換えてください
 4行目は固定です(ただしhttpsかhttpかは、npmのバージョンによって替わったことがあります)

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

VSCodeのRemote Developmentを使ってDocker上のNode.js、Redis環境で作業する

2019年5月に公開された、Visual Studio Code でリモートマシン、コンテナ、Windows Subsystem for Linux (WSL) 上のワークスペースを開くことができるようになる拡張機能群「Remote Development Extension Pack」を使ってみました。

remote-development0.JPG
https://code.visualstudio.com/docs/remote/remote-overview

この拡張パックを導入すると、手元の「Visual Studio Code」からリモート環境へ接続し、そこでアプリ開発等を行うことが可能になります。

今回は、Microsoftのレポジトリ VSCode Remote Try Nodeを元に、Node.jsからRedisを扱うDockerコンテナに接続する設定をやってみます。

1 Visual Studio Codeのバージョン確認

Stable 版では (version 1.35) リリース以降で Remote Development 拡張が利用可能です。
バージョンが古い場合は、Visual Studio Code の [ヘルプ]->[更新の確認] または https://code.visualstudio.com/updates 等から最新版にアップデートしてください。

2 拡張機能Remote Developmentのインストール

Visual Studio Codeで拡張機能"Remote Development"を検索し、インストールしてください。
vscode0.JPG

3 プロジェクトの構成

Microsoftのレポジトリ VSCode Remote Try Nodeをクローンし、最低限のディレクトリ構成を揃えた後、必要なファイルを加除していきます。

[Project Home]
|_ .devcontainer
|    |_  devcontainer.json 
|    |_ ubuntu-bionic-core-cloudimg-amd64-root.tar.gz
|  
|_ .vscode
|    |_  launch.json
|  
|_  build
|    |_  server.js
|_  src
|    |_  server
|         |_  main.ts
|_  store
|    |_  redis
|         |_  .gitkeep
| 
|_  Dockerfile
|_  docker-compose.yml
|_  package.json
|_ tsconfig.json
|_ tslint.json
|_  webpack.config.js

公式ではDockerfileを .devcontainer 以下に配置していますが、 ホームディレクトリ上のローカルフォルダ store/redis とDockerコンテナ上のディレクトリを同期してデータ永続化したいので、ホームディレクトリ直下に配置しています。

また、公式では、node:10イメージをベースを使っていますが、 今回は、Linuxイメージ上に npm, node.jsをインストールしたコンテナを作成し、redis コンテナとリンクする構成をやってみたいと思います。

当初、軽量Linuxの代表格alpineをベースにしようとしましたが、どうやら Stable版のVSCode上で動くRemote Developmentではalpineをサポートしていないようなので、やむなくMinimum Ubuntuを使うことにしました。

MInimum Ubuntuのイメージファイルは以下のレポジトリからダウンロードし、.devcontainer以下に配置しました。

https://github.com/tianon/docker-brew-ubuntu-core/blob/59aa7dfef17153ecc812adbf26516675ce67e8aa/bionic/Dockerfile

4 Remote Development の設定

devcontainer.json

devcontainer.json
{
    "name": "node.js and redis sample ",
    "dockerComposeFile": [
        "../docker-compose.yml"
    ],
    "service": "node",
    "appPort": 3000,
    "extensions": [
        "VisualStudioExptTeam.vscodeintellicode",
        "dbaeumer.vscode-eslint",
        "eg2.tslint"
    ],
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "shutdownAction": "none" 
}

主要な設定項目としては、

  • service で node.jsを稼働するコンテナのサービス名を指定
  • appPort で node.js上でlistenするportを指定
  • dockerComposeFileでdocker-compose.ymlの相対パスを指定
  • extensions でリモート上のVSCodeで使う拡張機能を追加

ちなみに、普段使っているVSCodeの拡張機能一覧は

code --list-extensions | xargs -L 1 echo code --install-extension

で取得できます。

5 Docker の設定

Dockerfile

Dokerfile
FROM scratch
ADD .devcontainer/ubuntu-bionic-core-cloudimg-amd64-root.tar.gz /
RUN set -xe \
    \
    && echo '#!/bin/sh' > /usr/sbin/policy-rc.d \
    && echo 'exit 101' >> /usr/sbin/policy-rc.d \
    && chmod +x /usr/sbin/policy-rc.d \
    \
    && dpkg-divert --local --rename --add /sbin/initctl \
    && cp -a /usr/sbin/policy-rc.d /sbin/initctl \
    && sed -i 's/^exit.*/exit 0/' /sbin/initctl \
    \
    && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup \
    \
    && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean \
    && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean \
    && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean \
    \
    && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages \
    \
    && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes \
    \
    && echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests

RUN rm -rf /var/lib/apt/lists/*

RUN sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list

RUN mkdir -p /run/systemd && echo 'docker' > /run/systemd/container

# Configure apt and install packages
RUN apt-get update && \
    yes | apt-get install \
    curl \
    git \
    npm \
    nodejs
WORKDIR /home
SHELL ["/bin/bash", "-c"]

基本的に、https://github.com/tianon/docker-brew-ubuntu-core/blob/59aa7dfef17153ecc812adbf26516675ce67e8aa/bionic/Dockerfile のままです。追加項目として、#Configure apt and install packages以下で、必要なモジュールをインストールするようにします。

docker-compose.yml

docker-compose.yml
version: '3'
services:
  node:
    build:
       context: .
       dockerfile: Dockerfile  
    container_name: node-container
    volumes:
      - .:/home
    ports:     
       - 3000:3000
    command: sh -c 'npm install & node build/server.js'
    links:
      - "redis"
  redis:
    restart: always
    container_name: redis-container
    image: redis:latest
    volumes:
        - ./store/redis:/data
    ports:
        - "6379:6379"
    command: redis-server --appendonly yes

上記のDockerfileを走らせて作成するnodeイメージと、Official Imageのredis:latestイメージをリンクします。
特記事項として、redis側でローカルのstore/redisとコンテナ側のdataフォルダを同期し、データの永続化を行っています。

6 package.jsonの設定

今回は、Webpackを使ってTypeScriptをトランスパイルする例です。

2019年7月現在の、webpackの最新バージョン 4.29.0 では Maximum Call Stackのエラーが出てしまうため、旧バージョンを指定しています。

package.json
{
  "name": "node.js and redis sample",
  "version": "1.0.0",
  "devDependencies": {
    "@types/app-root-path": "",
    "@types/express": "",
    "@types/node": "",
    "@types/redis": "",
    "path": "",
    "ts-loader": "",
    "tslint": "",
    "tslint-loader": "",
    "typescript": "",
    "webpack": "4.17.1",
    "webpack-cli": "",
    "webpack-node-externals": ""
  },
  "dependencies": {
    "app-root-path": "",
    "express": "",
    "redis": ""
  },
  "private": true
}

7 Node.jsによるサーバ設定

expressでWebサーバを立ち上げ、redisでPOSTの回数をカウントするという例です。

main.ts
'use strict';
import * as root from 'app-root-path';
import * as express from 'express';
import * as redis from 'redis';

/**
 * Configure Redis
 */
const client: redis.RedisClient = redis.createClient(6379, 'redis');
client.on('connect', () => console.log('Connected to Redis'));
client.set('visit', '0');

/**
 * Configure Web Server
 */
const app: express.Application = express();
app.use(express.static('.'));
app.post('/api',  (_req: express.Request, res: express.Response) => {
    client.get('visit', (_err: Error|null , visit: string) => {
      res.send('POST request received. Number of Visits:' + visit);
      client.set('visit', String(parseInt(visit, 10) + 1));
  });
});

// tslint:disable-next-line:typedef
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Server running on ${port}`));

8 実行

F1で拡張機能の一覧を表示するか、Visual Studioコードの左下の緑色のブラケットマークからRemoteデスクトップの機能一覧を表示します。
Inkedremote-development1.jpg

docker-compose up --build を既に一度走らせている場合は、「Attach to Running Container(水色)」を選択し、まだの場合は「Open Folder in Container(赤色)」で現在のホームディレクトリを指定すればdocker-compose up --build が自動的に走ります。ビルドに成功すると、Remote Development用のVSCodeのウィンドウが起動します。

Inkedremote-development2.jpg

後は開いたウィンドウ上で「フォルダを開く」から任意のフォルダを開くと、コンテナ上のファイルをVS Codeで編集することができます。

remote-development4.JPG

9 Redisの動作確認

 Remote Developmentとは直接関係ありませんが、Redisがきちんと動作しているか確認するには、curl -X POST(ローカル、コンテナ側のどちらからでも結構です) で以下のAPIを叩き、

 curl -X POST http://localhost:3000/api

以下のようにPOSTの通算回数が返ってくれば成功です。

POST request received. Number of Visits:[POSTの回数]

10 参考にさせていただいたサイト

下記のページを参考にさせていただきました。

https://code.visualstudio.com/updates/v1_35
https://qiita.com/yoskeoka/items/01c52c069123e0298660
https://qiita.com/mizuhof/items/7bc20538c9fe1edcba40
https://katsu-tech.hatenablog.com/entry/2017/10/11/233024
https://blog.manabusakai.com/2018/08/minimal-ubuntu-dockerfile/

なお、今回の構成はGithubで公開していますので、ご指摘などあればよろしくお願いいたします:neutral_face:

https://github.com/snst-lab/vscode-remote-try-node-typescript-redis

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

Nest.jsでSequelizeを使ってみる

前回、Nest.js を使ってみるでNest.js環境を構築しました。

今回はNode.js向けのORMであるSequelizeを導入してみます。

Sequelizeとは

Sequelize:http://docs.sequelizejs.com/

Nest.jsにSequelizeを組み込む

公式に手順が載っているため、それに従います

なお、今回使用するDBはPostgresです。

sequelize-typescriptのインストール

sequelize、sequelize-typescript、pg(postgres)、sequelizeの型定義パッケージをインストールします

$ npm install --save sequelize sequelize-typescript pg
$ npm install --save-dev @types/sequelize

DB接続準備

公式だと接続情報はコードにべた書きですが、環境ごとにDBを切り替えられるように設定ファイルで外だしします。

src/database/database.config.ts
export const config = {
    development: {
        host: process.env.POSTGRES_HOST,
        port: process.env.POSTGRES_PORT,
        database: process.env.POSTGRES_DB_NAME,
        username: process.env.POSTGRES_USER,
        password: process.env.POSTGRES_PASSWORD,
        dialect: 'postgres',
    },
    production: {
        // TODO 本番用
    }
}
src/database/database.providers.ts
import { Sequelize } from 'sequelize-typescript';
import { Cat } from '../cats/cat.entity';
import { config } from 'src/config/database.config';

export const databaseProviders = [
    {
        provide: 'SEQUELIZE',
        useFactory: async () => {
            const sequelize = new Sequelize(
                config[process.env.NODE_ENV || 'development']
            );
            sequelize.addModels([Cat]);
            await sequelize.sync();
            return sequelize;
        },
    },
];
database.module.ts
import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}

Catsテーブルアクセス用ファイル作成

公式の手順に従って、Catsテーブルにアクセスするためのファイルを準備します。

src/cats/cats.entity.ts
import { Table, Column, Model } from 'sequelize-typescript';

@Table
export class Cat extends Model<Cat> {
  @Column
  name: string;

  @Column
  age: number;

  @Column
  breed: string;
}
src/cats/cats.providers.ts
import { Cat } from './cat.entity';

export const catsProviders = [
  {
    provide: 'CATS_REPOSITORY',
    useValue: Cat,
  },
];
src/cats/cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { catsProviders } from './cats.providers';
import { DatabaseModule } from '../database/database.module';

@Module({
  imports: [DatabaseModule],
  controllers: [CatsController],
  providers: [
    CatsService,
    ...catsProviders,
  ],
})
export class CatsModule {}
src/cats/cats.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { Cat } from './cat.entity';

@Injectable()
export class CatsService {
  constructor(
    @Inject('CATS_REPOSITORY') private readonly CATS_REPOSITORY: typeof Cat) {}

  async findAll(): Promise<Cat[]> {
    return await this.CATS_REPOSITORY.findAll<Cat>();
  }
}
src/cats/cats.controller.ts
import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';
import { Cat } from './cat.entity';

@Controller({
  path: 'cats'
})
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get()
  getCats(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}

起動してみる

以下のようなdocker-compose.ymlを用意し、docker-compose upで起動してみます。

docker-compose.yml
version: '2'
services:
  nestjs-web:
    image: node:latest
    container_name: nestjs-web
    ports:
      - "3000:3000"
    links:
      - nestjs-db
    working_dir: /develop
    command: [sh, -c, 'npm install --unsafe-perm && npm run start:dev']
    volumes:
      - "./:/develop:z"
    environment:
      - "POSTGRES_HOST=192.168.33.20"
      - "POSTGRES_PORT=15432"
      - "POSTGRES_DB_NAME=postgres"
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=postgres"

  nestjs-db:
    image: postgres:latest
    container_name: nestjs-db
    ports:
      - "15432:5432"
    environment:
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=postgres"
    volumes:
      - "/data/db:/var/lib/postgresql/data:z"

ちゃんとCatsテーブルのCREATE文が発行されてますね。

image.png

DBにデータを投入

A5M2でDBにアクセスし、データを追加しておきます。

image.png

ブラウザでアクセス

http://192.168.33.20:3000/cats にアクセスします

image.png

追加した情報が取れました!

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

【最新サービス試用⑧】リクエスト管理やJSON出力結果整形等に便利なcurl拡張コマンドツールの「curlx」を試用。

  • 日々輩出される素晴らしき最新サービスを素早く試して、不鮮明な先見性を堂々と誇示する記事第八弾。
  • 歴史的偉人の集中力の記事の、収集作業に精を出している生活。
  • 今回は、curlでの出力の際に、Terminal上であらゆる高機能な作業が可能な「curlx」を試用することにしよう。

概要

  • レスポンス確認やAPI通信の際の際に用いる「curl」のリクエストの管理が捗るコマンドツール。
  • 「JSONでの出力結果の整形」や「リクエストのコレクション(グループ化)」等の機能を、GUIツール等を利用せずに、ターミナル内のみで可能。
  • GUIツールの「Postman」やJSON整形コマンドツールの「jq」の両方の機能を備えたようなツール。
  • 公式サイト
  • 公式Github

特徴

出力結果の整形

  • 可読が容易ではないcurlでのJSON出力結果を、cxでは整形して、見やすく表示してくれる。
  • jqを利用することなく、標準で整形してくれる。

リクエスト履歴の視覚化

  • リクエスト履歴の確認が容易に可能であることに加え、ステータスや通信形式、時間等の詳細情報が表として、わかりやすく確認できる。

リクエストのコレクション(グループ)化

  • リクエストをカテゴリごとにグループ化できるため、「よく投げるコマンドのエイリアス登録」や「内容別でのリクエストのグループ管理」が可能。
  • Postmanでのコレクション機能を、ターミナル内で利用が可能。

結果

  • テストAPIとして、LivedoorさんのWeather Hackを利用。

  • 下記のように、curlでは見づらいjson形式や文字化けが、簡単なコマンドで見やすくなる。

test.png

  • 通信形式やステータス結果等も含んだ、わかりやすい履歴の表示も可能。

status.png

  • よく使う出力等を、グループ化で整理して、簡単なコマンドでリクエストが可能。

collection_2.png

作業環境

  • Amazon Linux 2
  • Node.js v10.16.0
  • npm 6.9.0
  • Node.js環境が利用できれば、MacやWindowsでも可能。

インストール

# Node.jsのバージョン確認
$ node -v

# npmのバージョン確認
$ npm -v
  • 確認後、下記のコマンドをうち、「curlx」のインストールを行う。
# curlxのインストール
$ sudo npm install curlx -g

# バージョン確認
$ cx version

基本操作

  • curlxの基本操作は、下記。
    • 基本的にcurlコマンドをcxに置き換えるだけで可能。
内容 コマンド
通常リクエスト cx 接続先URL
※オプション指定なしで、ヘッダー出力やjson整形が可能。
リクエスト(オプション付き) cx -オプション URL
オプションは、curlと同様なため、curlをcxに置き換えるだけ。
例 : cx -X GET URL
リクエスト履歴確認 cx history
リクエストのグループ(コレクション)化 cx new collections
実行後、いくつかの質問に回答していく形で、作成していく
詳細は、下記の操作例を確認。
作成コレクションへのリクエストの追加 cx new request
コレクション作成同様、質問形式で追加していく
詳細は、下記の操作例を確認。
コレクション一覧 cx collections
idやコレクションリクエストでの実行 cx run <id or collection_id>
詳細は、下記の操作例を確認。
リクエストやコレクションの削除 cx delete <id or collectionname>
詳細は、下記の操作例を確認。
ヘルプページ確認 cx help
バージョン確認 cx version

操作例

通常リクエスト

  • 下記のコマンドをうち、URLでの通常リクエストを行う。
    • オプションは、curlと同様に扱えるため、cxに置き換えるだけでよい。
# 通常リクエスト
$ cx http://weather.livedoor.com/forecast/webservice/json/v1?city=471010

# オプション指定でのリクエスト
$ cx -X GET http://weather.livedoor.com/forecast/webservice/json/v1?city=471010

コレクションの作成〜実行

  • 下記のコマンドをうち、cxコマンドをグループ化することで、任意の名前とidでリクエストが可能。
# コレクション(グループ)を作成
$ cx new collection

✔ Name of your new collection … コレクション名(例:getWeather)入力

This collection already exists
✔ Would you like to add a new request to getWeather … リクエスト追加確認(例:yes)

✔ Enter complete request  eg: cx -X GET https://httpbin.org/get … 実行コマンド入力(例:cx -X GET URL)

✔ Give a name for your request … リクエスト名(例:getOkinawa)

# コレクション一覧確認
$ cx collections

┌────────────┬────────────────────┬────────┬──────────────────────────────┐
│ id         │ name               │ method │ url                          │
├────────────┼────────────────────┼────────┼──────────────────────────────┤
│ y2Q9JCOjL  │ getOkinawa         │ get    │ http://weather.livedoor.com… │
└────────────┴────────────────────┴────────┴──────────────────────────────┘


# id名でのリクエスト実行
# まず、history(履歴)内のid名での実行
$ cx history

┌────────────┬────────┬──────────────────────────────┬────────┬────────────┐
│ id         │ method │ url                          │ status │ timestamp  │
├────────────┼────────┼──────────────────────────────┼────────┼────────────┤
│ H0yIigcQv  │ get    │ http://weather.livedoor.com… │ 200    │ 2019-7-13  │
│            │        │                              │        │ 12:51 PM   │
├────────────┼────────┼──────────────────────────────┼────────┼────────────┤

$ cx run H0yIigcQv

{
  "pinpointLocations": [
    {
      "link": "http://weather.livedoor.com/area/forecast/4720100",
      "name": "那覇市"
    },
    {


# コレクション内のリクエストidでの実行
# ※コレクション内のidは、コレクション名も同時に明記する必要がある。
$ cx run getWeather y2Q9JCOjL

{
  "pinpointLocations": [
    {
      "link": "http://weather.livedoor.com/area/forecast/4720100",
      "name": "那覇市"
    },

コレクションへのリクエスト追加

  • 下記のコマンドをうち、既存コレクションに新規リクエストを追加
# コレクション確認
$ cx collections

┌────────────┬────────────────────┬────────┬──────────────────────────────┐
│ id         │ name               │ method │ url                          │
├────────────┼────────────────────┼────────┼──────────────────────────────┤
│ y2Q9JCOjL  │ getOkinawa         │ get    │ http://weather.livedoor.com… │
└────────────┴────────────────────┴────────┴──────────────────────────────┘

# リクエストの新規追加
$ cx new request

✔ Name of your new collection … コレクション名(getWeather)入力

✔ Enter complete request  eg: cx -X GET https://httpbin.org/get … 実行コマンド(例:cx URL)

✔ Give a name for your request … リクエスト名(getOsaka)

# コレクション一覧再確認
$ cx collections

┌────────────┬────────────────────┬────────┬──────────────────────────────┐
│ id         │ name               │ method │ url                          │
├────────────┼────────────────────┼────────┼──────────────────────────────┤
│ y2Q9JCOjL  │ getOkinawa         │ get    │ http://weather.livedoor.com… │
├────────────┼────────────────────┼────────┼──────────────────────────────┤
│ nG3nzD53k  │ getOsaka           │ get    │ http://weather.livedoor.com… │
└────────────┴────────────────────┴────────┴──────────────────────────────┘

リクエストidやコレクションidの削除

  • 下記のコマンドをうち、リクエストidやコレクションの削除を行う。
# id名でのリクエスト削除
$ cx delete H0yIigcQv

# コレクション内のid名でのリクエスト削除
$ cx delete getWeather:y2Q9JCOjL

操作履歴やコレクション確認

  • curlxの操作履歴やコレクション一覧は、下記のファイルで確認できる。
    • curlxの履歴やコレクションといった情報は、ルートフォルダの「cxdb」というフォルダに保存されている。
    • 簡単な履歴やコレクション確認の際は、上記の操作例での操作方法で可能。
# 操作履歴格納ファイルの中身確認
$ less ~/cxdb/history.json

{
  "history": [
    {
      "id": "UsVI7Oq9Y",
      "method": "get",
      "command": "curl -i \"http://weather.livedoor.com/forecast/webservice/json/v1?city=471010\"",
      "url": "http://weather.livedoor.com/forecast/webservice/json/v1?city=471010",
      "status": "200",
      "ts": "2019-7-12 11:58 PM"
    },
    {
      "id": "So_ybzFn3",
      "method": "get",
      "command": "curl -i \"http://weather.livedoor.com/forecast/webservice/json/v1?city=471010\"",
      "url": "http://weather.livedoor.com/forecast/webservice/json/v1?city=471010",
      "status": "200",
      "ts": "2019-7-13 12:01 AM"
    },
# コレクション一覧ファイルの中身確認
$ less ~/cxdb/collection.json

{
  "collections": {
    "getWeather": [
      {
        "id": "y2Q9JCOjL",
        "name": "getWeather",
        "method": "get",
        "command": "curl -i \"-X\" \"GET\" \"http://weather.livedoor.com/forecast/webservice/json/v1?city=471010\"",
        "url": "http://weather.livedoor.com/forecast/webservice/json/v1?city=471010"
      }

まとめ

  • 今回は、curlでのAPI結果整形ということで、「Terminalのみでの利用幅の拡大」による「パソコンの容量削減」を感慨深く染みながら、記事を書く。
  • 「利用機能による、GUIツールとCUIツールの併用」の誓いは、すぐさま「日毎の気分利用」に変化することを確信。
  • しばらく、この賢人ツールとの付き合いが続くと感じたため、より一層開発者礼拝を強化。

参考

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

Node.jsでGoogle Drive内の特定のファイルが特定のフォルダの配下にいるかどうかを調べる (Google Drive API v3)

Google Drive APIをNode.jsから触る以下の記事たちの続きです

GETメソッドを再帰的に使う

GETメソッドfieldsparentsを指定することで、親フォルダのIDを取得できます。
これを再帰的に繰り返していって、祖先を遡っていったときにフォルダ名が指定した名前のものが見つかったら終了です。

ちなみにGETメソッドの返却値はFILESのリファレンスを見ると確認できますが、けっこうたくさんあるので把握するのは大変そうですね。

スコープ

https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/drive.readonly
https://www.googleapis.com/auth/drive.metadata.readonly
https://www.googleapis.com/auth/drive.appdata
https://www.googleapis.com/auth/drive.metadata
https://www.googleapis.com/auth/drive.photos.readonly

なかなか多い。

簡単な実装

基本的な認証周りなどのコードは他の記事同様です。

get.js
省略

//特定のファイル(fileId)が特定フォルダ(folderName)の配下にいるか確認
const folderName = `定期発生`; 
const fileId = `xxxxxxxxxxxxxxxxxxxx`;

async function loop(drive, fileId, path = ''){
    //STEP1: IDからファイル情報を取得
    const params = {
        fileId: fileId,
        fields: 'parents,name,kind,mimeType,id,spaces'
    }
    const res = await drive.files.get(params);
    console.log('---',res.data);
    path = `/${res.data.name}${path}`;

    //STEP2: 親フォルダのIDをGET - ここが複数あるとうまく動かないときあるかも...
    const parentsFolderId = res.data.parents[0];

    //STEP3: 親フォルダを再帰的に探していく
    try {
        if(res.data.name === folderName){
            console.log(`このファイルは${folderName}の配下です。`, path);
        }else{
            await loop(drive, parentsFolderId, path);        
        }
    } catch (error) {
        console.log(`このファイルは${folderName}の配下ではありません。`)
    }
}

async function main(auth) {
    const drive = google.drive({version: 'v3', auth});
    await loop(drive, fileId);
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む