20210322のNode.jsに関する記事は5件です。

TypeScript + express-graphql + TypeORM on Node.js ( for MySQL ) 環境を構築したった

はじめに

はじめまして。突然ですが、GraphQL、めちゃくちゃ良い技術です。
Rails に載った GraphQL を業務で使ってますが、フロントエンド開発がフッ軽になります。

もっと GraphQL に詳しくなりたい。でも、現在、フロントエンドエンジニアとして勤務中の私には、実務で GraphQL を触ることができたとしても せいぜい Type をちょろっと修正するくらい。

そこで、趣味で書いてる Vue.js 製 WEB アプリの API に GraphQL を採用することにしました。
導入から API として動かすところまでを勉強がてら実装したので、せっかくだし最小限の構成をご紹介します。備忘録も兼ねて。

・・・Rails に対してのモチベーションが高くない ☺️ ので、今回は express に載せてます。

実際にやってみた

TypeScript 使ってますが、サンプルコードの中では 面倒臭いので 厳密に取り扱っていない箇所があります。そーりー。

下準備

package.json を用意

package.json
{
  "name": "graphql-on-express",
  "dependencies": {
    "@types/cors": "^2.8.10",
    "@types/express": "^4.17.11",
    "@types/express-graphql": "^0.9.0",
    "@types/mysql": "^2.15.18",
    "@types/node": "^14.14.35",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "express-graphql": "^0.12.0",
    "graphql": "^15.5.0",
    "mysql": "^2.17.1",
    "typeorm": "^0.2.31",
    "typescript": "^4.2.3"
  },
  "devDependencies": {
    "ts-node": "^9.1.1",
    "tsconfig-paths": "^3.9.0"
  },
}

DB まわりのアレコレは TypeORM というライブラリに任せます。

・・・package.json で足りない項目がある場合はテキトーに埋めてください ?

TypeScript、TypeORM のコンフィグを用意

tsconfig.json
{
  "compilerOptions": {
    "sourceMap": false,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5",
    "lib": [
      "es2018",
      "dom"
    ],
    "moduleResolution": "node",
    "removeComments": true,
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": false,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "strictFunctionTypes": false,
    "baseUrl": "./",
    "paths": {
      "@/*": [
        "src/*"
      ],
    },
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
  },
  "include": [
    "./src/**/*.ts"
  ]
}
ormconfig.json
{
  "type": "mysql",
  "host": "Your DB endpoint",
  "port": 3306,
  "username": "Your DB username",
  "password": "Your DB password",
  "database": "Your DB name",
  "synchronize": false,
  "logging": false,
  "entities": [
    "src/database/entity/**/*.ts"
  ],
  "migrations": [
    "src/database/migration/**/*.ts"
  ],
  "subscribers": [
    "src/database/subscriber/**/*.ts"
  ],
  "cli": {
    "entitiesDir": "src/database/entity",
    "migrationsDir": "src/database/migration",
    "subscribersDir": "src/database/subscriber"
  }
}

node modules をインストール

$ npm i

データまわりの作業

Entity を用意

データベースとプログラムとの間でマッピングされたデータが、どのようなデータ構造をとるのかを定義します。
TypeORM では、このようなデータモデルを Entity という名称で表現するようです。
一般的な MVC フレームワークにおいて、Model と呼ばれているモノにイメージは近いですが、Model と違ってロジックを持たせることはあまり想定してなさ気です。だから、あくまでも "Model" じゃなくて ただの "Entity" (実体) なのかと思いました (小並感

src/database/entity/user.ts
import { Entity, BaseEntity, Column, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class User extends BaseEntity {
  @PrimaryGeneratedColumn('increment')
  id!: number;

  @Column({ nullable: false })
  name!: string;
}

サンプルなので、id と name というカラムだけをもったシンプルな構造を用意します。

マイグレーションする

なんと、TypeORM はマイグレーションの機能まで提供してくれています。ありがとう。

$ npx ts-node node_modules/.bin/typeorm migration:generate -n user

上記を実行すると、src/database/migration/xxxxxxxxxxxxx-user.ts というファイルが生成されます。

続けて、以下を実行します。

$ npx ts-node node_modules/.bin/typeorm migration:run

ずらずらと SQL の実行ログが流れ・・・

(省略)

Migration userxxxxxxxxxxxxx has been executed successfully.
query: COMMIT

最後にこんなログが出力されれば成功です。

ターミナルから MySQL に直接ログインできる方は実際にテーブルを確認してみてください。

(省略)

mysql> desc user;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int          | NO   | PRI | NULL    | auto_increment |
| name        | varchar(255) | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
2 rows in set (0.02 sec)

こんな感じになってるはず。

・・・テーブル名的には users であってほしいけど、Entity を複数形にしなきゃいけないのかな ?

ロジックまわりの作業

Type を定義

src/schema/fields/user/types.ts
import { GraphQLObjectType, GraphQLNonNull, GraphQLString, GraphQLInt, GraphQLInputObjectType } from 'graphql';

export const UserType = new GraphQLObjectType({
  name: 'User',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
    name: {
      type: new GraphQLNonNull(GraphQLString),
    }
  }
});

export const FetchUserInput = new GraphQLInputObjectType({
  name: 'FetchUserInput',
  fields: {
    id: {
      type: new GraphQLNonNull(GraphQLInt),
    },
  }
});

export const CreateUserInput = new GraphQLInputObjectType({
  name: 'CreateUserInput',
  fields: {
    name: {
      type: new GraphQLNonNull(GraphQLString),
    },
  }
});

Schema を定義

実際に運用する際は、Entity に対して query と mutation があり、場合によっては、そこからさらにバリエーションが派生する、なんてこともあります。
ファイルを細かく分けていて、サンプルコードをみてるだけだと「冗長じゃね?」と思うかもしれませんが、上記の理由から処理が増えることを視野に入れてこうしてます。

src/schema/index.ts
import { GraphQLSchema } from "graphql";
import { queryType as query, mutationType as mutation } from "./fields";

export const schema = new GraphQLSchema({
  query,
  mutation,
});
src/schema/fields/index.ts
import { GraphQLObjectType } from 'graphql';
import { userField } from './user';

export const queryType = new GraphQLObjectType({
  name: 'Query',
  fields: {
    ...userField.query,
  }
})

export const mutationType = new GraphQLObjectType({
  name: 'Mutation',
  fields: {
    ...userField.mutation,
  }
})
src/schema/fields/user/index.ts
import { userQuery as query } from './query';
import { userMutation as mutation } from './mutation';

export const userField = {
  query,
  mutation,
};
src/schema/fields/user/query.ts
import { GraphQLNonNull } from 'graphql';
import * as resolvers from './resolvers';
import { FetchUserInput, UserType } from './types';

const fetchUsers = {
  type: UserType,
  args: {
    input: {
      type: new GraphQLNonNull(FetchUserInput)
    }
  },
  resolve: resolvers.fetchUsers,
}

export const userQuery = {
  fetchUsers,
}
src/schema/fields/user/mutation.ts
import { GraphQLNonNull, GraphQLList } from 'graphql';
import * as resolvers from './resolvers';
import { UserType, CreateUserInput } from './types';

const createUser = {
  type: new GraphQLList(UserType),
  args: {
    input: {
      type: new GraphQLNonNull(CreateUserInput)
    }
  },
  resolve: resolvers.createUser
}

export const userMutation = {
  createUser,
}

"DB への問い合わせ" や "結果を受け取って返却する" などのコアとなる処理を用意

src/schema/fields/user/resolvers.ts
import { User } from "@/database/entity/user"
import { find, findOne, insert } from "../crud-assistant"

// e.g.
type CreateUserArgs = {
  input: {
    // any
  }
}

// e.g.
type FetchUserArgs = {
  input: {
    // any
  }
}

// e.g.
type FetchUsersArgs = {
  input: {
    // any
  }
}

export const createUser = async (args: CreateUserArgs): Promise<typeof User> => {
  return new Promise(async (resolve, reject) => {
    const insertInput = args.input
    const result = await insert<typeof User, CreateUserArgs["input"]>(User, insertInput)

    if (!result) {
      reject()
      return
    }

    const findOneInput = args.input
    const user = await findOne<typeof User, FetchUserArgs["input"]>(User, findOneInput)

    if (user) {
      resolve(user)
    } else {
      reject()
    }
  })
}

export const fetchUsers = async (args: FetchUsersArgs): Promise<Array<typeof User>> => {
  return new Promise(async (resolve, reject) => {
    const findInput = args.input
    const users = await find<typeof User, FetchUsersArgs["input"]>(User, findInput)

    if (users) {
      resolve(users)
    } else {
      reject()
    }
  })
}

CRUD の処理を共通化しておきます。
TypeORM の Repository のメソッドと同名で公開。

src/schema/fields/crud-assistant.ts
import { BaseEntity, createConnection, getRepository, InsertResult } from "typeorm"

export const insert = async<E extends typeof BaseEntity, I>(Entity: E, input: I): Promise<InsertResult | null> => {
  const connection = await createConnection()
  const repository = getRepository<E>(Entity)

  try {
    return new Promise(async (resolve, reject) => {
      const result = await repository
        .insert({
          ...input
        })
        .catch(async (e) => {
          reject()
        })

      await connection.close()

      resolve(result || null)
    })
  } catch (e) {
    await connection.close()
    return Promise.resolve(e)
  }
}

export const findOne = async<E extends typeof BaseEntity, I>(Entity: E, input: I): Promise<E | null> => {
  const connection = await createConnection()
  const repository = getRepository<E>(Entity)

  try {
    return new Promise(async (resolve, reject) => {
      const result = await repository
        .findOne({
          ...input
        })
        .catch(async (e) => {
          reject()
        })

      await connection.close()

      resolve(result || null)
    })
  } catch (e) {
    await connection.close()
    return Promise.resolve(e)
  }
}

export const find = async <E extends typeof BaseEntity, I>(Entity: E, input: I): Promise<E[] | null> => {
  const connection = await createConnection()
  const repository = getRepository<E>(Entity)

  try {
    return new Promise(async (resolve, reject) => {
      const result = await repository
        .find({
          ...input
        })
        .catch(async (e) => {
          reject()
        })

      await connection.close()

      resolve(result || null)
    })
  } catch (e) {
    await connection.close()
    return Promise.resolve(e)
  }
}

これでようやくロジックまわりのファイルが揃いました。

サーバまわりの作業

エントリポイントを用意

src/index.ts
import * as express from 'express'
import { graphqlHTTP } from 'express-graphql'
import * as cors from 'cors'
import { schema } from './schema'

const port = 4000
const app = express()
app.use(cors())
app.use(express.static('./'));
app.use('/', graphqlHTTP({
  schema,
  graphiql: true
}))

app.listen(port, () => {
  console.log(`Started server, http://localhost:${port}`)
});

エントリポイントを用意したら、

$ npx ts-node -r tsconfig-paths/register src/index.ts

を実行。

これで、http://localhost:4000 にアクセスすると Graph i QL という GUI が表示されるようになります。
API としてのリクエストには、POST を用います。

Vue アプリ側からは Vue Apollo 経由で API を call してます。その話はまたどこかでするかもしれないししないかもしれない。

おわりに

GraphQL について

冒頭でも触れましたが、フロントエンドの開発においてめちゃくちゃ便利です。
良い技術なわりに、あまり世に浸透していない気がする。もったいない ?

TypeORM について

便利ではありますが、提供してる型が微妙に扱いにくいと感じるところがあったり、(当たり前だけど) GraphQL 側にも型の指定が必要なので TypeORM ↔️ GraphQL 間で同じデータを指してるのに構造の定義が二重管理になっちゃったりと、小さな課題があるので要改善。暇なときに TypeORM 側のコードから GraphQL の Type 定義のコードを自動生成するようなスクリプトを書きたい。(すでに誰かが作ってるかも
まあ、使いこなせれば良きなライブラリな気はします。あと、日本語の文献が豊富ではないです。

おしまい。

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

Nodeについて調べてみた

「JavaScript」の勉強をしているとターミナルにNode.jsに関して入力することがあったりしましたがそもそも「Nodeってなに?」と思ったので調べてみました。

Nodeとは

Nodeとは、節、結節(点)、節点、交点、中心点、集合点、こぶ、膨らみ、などの意味を持つ英単語。
ITの分野では網状構造の構成要素などをこのように呼ぶ。

複数の要素が結びついた構造体において、個々の要素のことをノードという。
ノードを結びつける線や繋がりは「エッジ」あるいは「リンク」という。

例えば [サーバ]ー[ルータ]ー[サーバ]などの構成のネットワークを点と線のみで結ぶと
●ー●ー●の点の部分(パソコン、ルータ、サーバ)が「ノード」

Node.jsとは?

サーバサイドで動くJavaScriptだと思っていましたが、
Node.jsはサーバサイドでJavaScriptを実行できるためのプラットフォームという理解が正しそう。

リアルタイムWebなどの分野でNode.jsが採用される事例(MicrosoftやYahoo等)がある
※リアルタイムWEB = リアルタイムな反応が必要な場所(FacebookやTwitter、Googleスプレッドシート等)

例えば、LAMP環境だと
・WEBサーバとWEBブラウザを常時接続する必要がある
・データを保存し続け、Webブラウザ側に表示し続ける必要がある

これら問題でチャット画面をみるのに必要以上に時間を要するらしいが、Node.jsではこれらの機能を比較的簡単なコードで実装できる。

参考にしたサイト

参考1 ( https://e-words.jp/w/%E3%83%8E%E3%83%BC%E3%83%89.html)
参考2 (https://wa3.i-3-i.info/word1300.html
参考3( https://eng-entrance.com/what-is-nodejs
参考4( http://www.tohoho-web.com/ex/nodejs.html
参考5( https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb ) 

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

Node.jsについて調べてみた

「JavaScript」の勉強をしているとターミナルにNode.jsに関して入力することがあったりしましたがそもそも「Nodeってなに?」と思ったので調べてみました。

その前に、JavaScriptとNodeについても簡単におさらいしてみます。

JavaScriptとは

元々はブラウザやHTMLページを操作するためのプログラミング言語として1995年に誕生。
当初はブラウザ間の互換性が低くて普及しませんでしたが、「Ajax」という機能が発明されてから人気が高まった。

Ajax とはJavaScriptとサーバーの通信を非同期に行い、動的なデータを一部だけ書き換える方法のことですが、詳しくは下記参考
参考①:( http://pikawaka.com/word/ajax )

現在は殆どのサイトでJavaScriptは採用されており、画像を切り替えたり動かしたりする時にJavaScriptは書かれている。

特に重要な役割を端的に書くと下記3点になる。
・ブラウザで表示されているHTMLやCSSを書き換える。
・ブラウザに表示されているHTMLやCSSを情報から読み取る。
・ブラウザに表示されているHTMLやCSSをリアルタイムに書き換えることができる。

サーバーサイドの言語のRubyやPHPなどは「パソコン上で動作する」のに対し、
JavaScriptは「ブラウザ上で動作する」のが特徴。

Nodeとは

Nodeとは、「点と線で構成図を書いたの線の部分のこと」

複数の要素が結びついた構造体において、個々の要素のことをノードという。
ノードを結びつける線や繋がりは「エッジ」あるいは「リンク」という。

例えば [サーバ]ー[ルータ]ー[サーバ]などの構成のネットワークを点と線のみで結ぶと
●ー●ー●の点の部分(パソコン、ルータ、サーバ)が「ノード」と呼ばれる。

参考②:( https://e-words.jp/w/%E3%83%8E%E3%83%BC%E3%83%89.html )
参考③:( https://wa3.i-3-i.info/word1300.html

DOMとDOM操作している時に出てくるNodeについて

JavaScriptの登場初期はブラウザごとに制御方法が違っていたので、ブラウザごとにJavaScriptのコードを用意する必要があったが、制御方法を統一するためにDOM(Document Object Model)という仕様が生まれた。
DOMに対応しているブラウザで閲覧すれば同じ動作が期待できる。

DOM(Document Object Model)はプログラムから「HTML文書」や「XML文書」を利用するための標準化された仕様。

HTML文書は「タグ」「属性」「値」「文書」などの部品で構成されており、HTML文章がブラウザに読み込まれるとJavaScript内でこれらの部品1つ1つが「DOM オブジェクト」として自動的に生成される。

参考④(https://hakuhin.jp/js/dom.html#DOM_00

「DOM オブジェクト」であれば、共通して利用できる基本的な機能として、Nodeというインターフェースが定められている。「Node インターフェース」を使うと木構造(ツリー構造)の親子関係を構築することができる。

インターフェース とは「何かと何かがくっついている部分のこと。コンピュータの世界では接点、接続口、境界面」などがイメージできるところで使用されている広い意味で利用される用語。参考⑤( https://wa3.i-3-i.info/word11374.html )

・ノードの種類について上記参考サイトから転載させていただきます。
図の方がわかりやすいので
スクリーンショット 2021-03-22 14.37.38.png

Node.jsとは?

こちらに関しては参考⑥( http://www.tohoho-web.com/ex/nodejs.html )に記載されててる内容を基にわからない単語を順次補足する形で下記にメモを取っています。
(下記の画像表示内容を補足する形で記載)
スクリーンショット 2021-03-22 17.05.53.png

[内容まとめ]
・Node.jsはサーバサイドでJavaScriptを実行できるためのプラットフォーム
・npm(Node Package Manager)と呼ばれるパッケージ管理ツールを同梱。
・ノンブロッキングI/O と イベントループ アーキテクチャにより、10K問題 (クライアント1万台レベルになると性能が極端に悪化する問題) に対応。

ノンブロッキングI/O:処理を行っている最中も並行して他の処理はできるだけ進む。I/Oは出入力を意味する。(Input / Output)。参考⑦( https://wa3.i-3-i.info/word1621.html)
イベントループ:何かが起きた時に処理の順番を決めて進めること。参考⑧( https://rightcode.co.jp/blog/information-technology/node-js-event-loop-overview )
アーキテクチャ:IT業界では「システムに求められることを効率よく行っていくために必要な機能や相互データの更新を定める枠組み」を指す。

・通信やファイルの読み書きをノンブロッキングI/Oで処理するため、スレッドが I/O 待ちになる頻度が少なく、効率的。

スレッド:「処理の流れ」。マルチスレッドは「同時実行されているその処理」を意味する。似た言葉で「マルチプロセス」があり、それらは「複数の処理を同時に実行する」といったものだが、データ管理の点で意味が異なる。マルチプロセスでは、各プロセスにおいて、データは独立している。マルチスレッドでは、各スレッドにおいて一部を除きデータを共有している。参考⑨( http://www.itsenka.com/contents/development/java/topics/thread1.html

・クライアントからパケットを読み込む、ファイルの次のブロックを読み出すなどすべてがイベント処理で実装されている。

パケット :「データを通信する上で細かく分割されたデータ」
参考⑩( https://wa3.i-3-i.info/word176.html )

・基本的にはシングルスレッドだが、内部では暗号化などの重い処理を複数スレッドで処理。
・基本的にはシングルプロセスだが、JavaScript から fork() を呼び出すことで、マルチプロセスも可能。

fork():元となるプロセス(親プロセス)を複製し PID (プロセス ID)と PPID (親プロセス ID) が 異なるプロセス(子プロセス)を生成すること。
参考11( https://www.gadgety.net/shin/tips/unix/ipc/fork.html )

プロセス :メモリを使って実行されているプログラムの1つ。≒実行中のプログラム。プロセスは処理の過程で別のプロセスを作る場合がある。
参考12( https://wa3.i-3-i.info/word11033.html

メモリ :PCで処理に必要なデータを一時保管しておくパーツのこと。
参考13( https://pikawaka.com/word/memory )

・ライセンスはMITライセンス。商用利用可能。

MITラインセンス :オープンソースライセンス(ソースコードが無償で公開され、複製・改良・再配布が誰でも自由にできるもの)の1つで利用許諾のための条件などを定めているもの。
参考14( https://yamory.io/blog/about-mit-License/

・Node.js 上のフレームワークとして、Express, Meteor, Sails, Koa, LoobBack などがある。
・MEAN(MongoDB+Express+AngularJS+Node.js)と呼ばれる構成で利用されることも多い。
・HTTP 通信のみでなく、TCP や UDP 通信も可能。

HTTP :HTML文書などのを取り出すことを可能にするプロトコル。
プロトコル :コンピューター同士の通信をする際の手順や規格のこと。情報を送り出す端末の選定、データの形式、パケットの構成、エラーの対処などを取り決めた通信の約束事。
参考15( https://www.otsuka-shokai.co.jp/words/protocol.html

TCP :(Transmission Control Protocol)の略。安全性重視で通信するための通信方法。「送ったデータが相手に届いたか、その都度確認しながら通信するやり方」
参考16( https://wa3.i-3-i.info/word19.html
参考17( https://www.infraexpert.com/study/tcpip.html

UDP :(User Datagram Protocol)転送速度は早いが、送ったデータが相手に届いたか確認しないで行う通信方法。音楽や映像などのリアルタイム性のあるデータを転送する場合、複数の相手に同じデータを同時に転送する場合、信頼性の必要がなく、少量のデータを転送したい場合などに利用される。
参考18( https://www.infraexpert.com/study/tcpip12.html

・WebSockerサーバとして利用されることも多い。
WebSocket :リアルタイムWeb技術の一種であり、リアルタイムかつ双方向な通信を実現するプロトコル。
参考19( https://www.atmarkit.co.jp/ait/articles/1603/14/news015.html )

・比較的小規模で、高パフォーマンスを要求されるプロジェクトでの利用が多い。
・AWS Lambda, PayPal, Walmart, Uber など大量アクセス領域で利用されている。

参考にしたサイト

参考1(http://pikawaka.com/word/ajax)
参考2( https://e-words.jp/w/%E3%83%8E%E3%83%BC%E3%83%89.html )
参考3( https://wa3.i-3-i.info/word1300.html
参考4( https://hakuhin.jp/js/dom.html#DOM_00
参考5( https://wa3.i-3-i.info/word11374.html )
参考6( http://www.tohoho-web.com/ex/nodejs.html
参考7( https://wa3.i-3-i.info/word1621.html)
参考8( https://rightcode.co.jp/blog/information-technology/node-js-event-loop-overview )
参考9( http://www.itsenka.com/contents/development/java/topics/thread1.html
参考10( https://wa3.i-3-i.info/word176.html )
参考11( https://www.gadgety.net/shin/tips/unix/ipc/fork.html )
参考12( https://wa3.i-3-i.info/word11033.html
参考13( https://pikawaka.com/word/memory )
参考14( https://yamory.io/blog/about-mit-License/
参考15( https://www.otsuka-shokai.co.jp/words/protocol.html
参考16( https://wa3.i-3-i.info/word19.html
参考17( https://www.infraexpert.com/study/tcpip.html
参考18( https://www.infraexpert.com/study/tcpip12.html
参考19( https://www.atmarkit.co.jp/ait/articles/1603/14/news015.html )

Qiita記事だとこちらもすごく纏まっておりました
参考20( https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb ) 

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

Node.js

「JavaScript」の勉強をしているとターミナルにNode.jsに関して入力することがあったりしましたがそもそも「Nodeってなに?」と思ったので調べてみました。

その前に、JavaScriptとNodeについても簡単におさらいしてみます。

JavaScriptとは

元々はブラウザやHTMLページを操作するためのプログラミング言語として1995年に誕生。
当初はブラウザ間の互換性が低くて普及しませんでしたが、「Ajax」という機能が発明されてから人気が高まった。

Ajax とはJavaScriptとサーバーの通信を非同期に行い、動的なデータを一部だけ書き換える方法のことですが、詳しくは下記参考
参考①:( http://pikawaka.com/word/ajax )

現在は殆どのサイトでJavaScriptは採用されており、画像を切り替えたり動かしたりする時にJavaScriptは書かれている。

特に重要な役割を端的に書くと下記3点になる。
・ブラウザで表示されているHTMLやCSSを書き換える。
・ブラウザに表示されているHTMLやCSSを情報から読み取る。
・ブラウザに表示されているHTMLやCSSをリアルタイムに書き換えることができる。

サーバーサイドの言語のRubyやPHPなどは「パソコン上で動作する」のに対し、
JavaScriptは「ブラウザ上で動作する」のが特徴。

Nodeとは

Nodeとは、「点と線で構成図を書いたの線の部分のこと」

複数の要素が結びついた構造体において、個々の要素のことをノードという。
ノードを結びつける線や繋がりは「エッジ」あるいは「リンク」という。

例えば [サーバ]ー[ルータ]ー[サーバ]などの構成のネットワークを点と線のみで結ぶと
●ー●ー●の点の部分(パソコン、ルータ、サーバ)が「ノード」と呼ばれる。

参考②:( https://e-words.jp/w/%E3%83%8E%E3%83%BC%E3%83%89.html )
参考③:( https://wa3.i-3-i.info/word1300.html

DOMとDOM操作している時に出てくるNodeについて

JavaScriptの登場初期はブラウザごとに制御方法が違っていたので、ブラウザごとにJavaScriptのコードを用意する必要があったが、制御方法を統一するためにDOM(Document Object Model)という仕様が生まれた。
DOMに対応しているブラウザで閲覧すれば同じ動作が期待できる。

DOM(Document Object Model)はプログラムから「HTML文書」や「XML文書」を利用するための標準化された仕様。

HTML文書は「タグ」「属性」「値」「文書」などの部品で構成されており、HTML文章がブラウザに読み込まれるとJavaScript内でこれらの部品1つ1つが「DOM オブジェクト」として自動的に生成される。

参考④(https://hakuhin.jp/js/dom.html#DOM_00

「DOM オブジェクト」であれば、共通して利用できる基本的な機能として、Nodeというインターフェースが定められている。「Node インターフェース」を使うと木構造(ツリー構造)の親子関係を構築することができる。

インターフェース とは「何かと何かがくっついている部分のこと。コンピュータの世界では接点、接続口、境界面」などがイメージできるところで使用されている広い意味で利用される用語。参考⑤( https://wa3.i-3-i.info/word11374.html )

・ノードの種類について上記参考サイトから転載させていただきます。
図の方がわかりやすいので
スクリーンショット 2021-03-22 14.37.38.png

Node.jsとは?

こちらに関しては参考⑥( http://www.tohoho-web.com/ex/nodejs.html )に記載されててる内容を基にわからない単語を順次補足する形で下記にメモを取っています。
(下記の画像表示内容を補足する形で記載)
スクリーンショット 2021-03-22 17.05.53.png

[内容まとめ]
・Node.jsはサーバサイドでJavaScriptを実行できるためのプラットフォーム
・npm(Node Package Manager)と呼ばれるパッケージ管理ツールを同梱。
・ノンブロッキングI/O と イベントループ アーキテクチャにより、10K問題 (クライアント1万台レベルになると性能が極端に悪化する問題) に対応。

ノンブロッキングI/O:処理を行っている最中も並行して他の処理はできるだけ進む。I/Oは出入力を意味する。(Input / Output)。参考⑦( https://wa3.i-3-i.info/word1621.html)
イベントループ:何かが起きた時に処理の順番を決めて進めること。参考⑧( https://rightcode.co.jp/blog/information-technology/node-js-event-loop-overview )
アーキテクチャ:IT業界では「システムに求められることを効率よく行っていくために必要な機能や相互データの更新を定める枠組み」を指す。

・通信やファイルの読み書きをノンブロッキングI/Oで処理するため、スレッドが I/O 待ちになる頻度が少なく、効率的。

スレッド:「処理の流れ」。マルチスレッドは「同時実行されているその処理」を意味する。似た言葉で「マルチプロセス」があり、それらは「複数の処理を同時に実行する」といったものだが、データ管理の点で意味が異なる。マルチプロセスでは、各プロセスにおいて、データは独立している。マルチスレッドでは、各スレッドにおいて一部を除きデータを共有している。参考⑨( http://www.itsenka.com/contents/development/java/topics/thread1.html

・クライアントからパケットを読み込む、ファイルの次のブロックを読み出すなどすべてがイベント処理で実装されている。

パケット :「データを通信する上で細かく分割されたデータ」
参考⑩( https://wa3.i-3-i.info/word176.html )

・基本的にはシングルスレッドだが、内部では暗号化などの重い処理を複数スレッドで処理。
・基本的にはシングルプロセスだが、JavaScript から fork() を呼び出すことで、マルチプロセスも可能。

fork():元となるプロセス(親プロセス)を複製し PID (プロセス ID)と PPID (親プロセス ID) が 異なるプロセス(子プロセス)を生成すること。
参考11( https://www.gadgety.net/shin/tips/unix/ipc/fork.html )

プロセス :メモリを使って実行されているプログラムの1つ。≒実行中のプログラム。プロセスは処理の過程で別のプロセスを作る場合がある。
参考12( https://wa3.i-3-i.info/word11033.html

メモリ :PCで処理に必要なデータを一時保管しておくパーツのこと。
参考13( https://pikawaka.com/word/memory )

・ライセンスはMITライセンス。商用利用可能。

MITラインセンス :オープンソースライセンス(ソースコードが無償で公開され、複製・改良・再配布が誰でも自由にできるもの)の1つで利用許諾のための条件などを定めているもの。
参考14( https://yamory.io/blog/about-mit-License/

・Node.js 上のフレームワークとして、Express, Meteor, Sails, Koa, LoobBack などがある。
・MEAN(MongoDB+Express+AngularJS+Node.js)と呼ばれる構成で利用されることも多い。
・HTTP 通信のみでなく、TCP や UDP 通信も可能。

HTTP :HTML文書などのを取り出すことを可能にするプロトコル。
プロトコル :コンピューター同士の通信をする際の手順や規格のこと。情報を送り出す端末の選定、データの形式、パケットの構成、エラーの対処などを取り決めた通信の約束事。
参考15( https://www.otsuka-shokai.co.jp/words/protocol.html

TCP :(Transmission Control Protocol)の略。安全性重視で通信するための通信方法。「送ったデータが相手に届いたか、その都度確認しながら通信するやり方」
参考16( https://wa3.i-3-i.info/word19.html
参考17( https://www.infraexpert.com/study/tcpip.html

UDP :(User Datagram Protocol)転送速度は早いが、送ったデータが相手に届いたか確認しないで行う通信方法。音楽や映像などのリアルタイム性のあるデータを転送する場合、複数の相手に同じデータを同時に転送する場合、信頼性の必要がなく、少量のデータを転送したい場合などに利用される。
参考18( https://www.infraexpert.com/study/tcpip12.html

・WebSockerサーバとして利用されることも多い。
WebSocket :リアルタイムWeb技術の一種であり、リアルタイムかつ双方向な通信を実現するプロトコル。
参考19( https://www.atmarkit.co.jp/ait/articles/1603/14/news015.html )

・比較的小規模で、高パフォーマンスを要求されるプロジェクトでの利用が多い。
・AWS Lambda, PayPal, Walmart, Uber など大量アクセス領域で利用されている。

参考にしたサイト

参考1(http://pikawaka.com/word/ajax)
参考2( https://e-words.jp/w/%E3%83%8E%E3%83%BC%E3%83%89.html )
参考3( https://wa3.i-3-i.info/word1300.html
参考4( https://hakuhin.jp/js/dom.html#DOM_00
参考5( https://wa3.i-3-i.info/word11374.html )
参考6( http://www.tohoho-web.com/ex/nodejs.html
参考7( https://wa3.i-3-i.info/word1621.html)
参考8( https://rightcode.co.jp/blog/information-technology/node-js-event-loop-overview )
参考9( http://www.itsenka.com/contents/development/java/topics/thread1.html
参考10( https://wa3.i-3-i.info/word176.html )
参考11( https://www.gadgety.net/shin/tips/unix/ipc/fork.html )
参考12( https://wa3.i-3-i.info/word11033.html
参考13( https://pikawaka.com/word/memory )
参考14( https://yamory.io/blog/about-mit-License/
参考15( https://www.otsuka-shokai.co.jp/words/protocol.html
参考16( https://wa3.i-3-i.info/word19.html
参考17( https://www.infraexpert.com/study/tcpip.html
参考18( https://www.infraexpert.com/study/tcpip12.html
参考19( https://www.atmarkit.co.jp/ait/articles/1603/14/news015.html )

Qiita記事だとこちらもすごく纏まっておりました
参考20( https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb ) 

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

discordjs/rpcを使ってPCのDiscordをスマホからミュートにしたい

動機

コロナ渦の大学生なので,ずっと家にいて暇です.常に仲間とDiscordのVCをつないで作業をしています.

ふとトイレに行くときに,PCのマイクをミュートにし忘れることがあります.
イヤホンはBluetoothなので音は聞こえているのですが,トイレとかキッチンに行った時とかにミュートにし忘れることがあって不便です.
そこで,離れたところからスマホでPCのDiscordをミュートにできたらと思っていたのですが,DiscordのRPCなAPIで実現できそうだったので試してみました.

環境

  • ThinkPad X270
  • Arch Linux
  • Node.js v14.16.0
  • discord-rpc v3.2.0
  • express
  • Discord

Discordのアプリを,Node.jsで動くエージェントサーバーで操作する感じです.
Node.jsのサーバー上で,ExpressによるWebサーバーとDiscordRPCクライアントが走っています.
Webサーバーがリクエストを受け取ったらDiscordのミュートをトグルする,といった形です.

準備

Discordの
- ClientID
- ClientSecret
- AccessToken

が必要になります.
AccessTokenのScopesについては,私の場合は,
- rpc
- rpc.api
- identify
のトークンを発行しました.

ソース

const DiscordRPC = require('discord-rpc')
const express = require('express')

const clientId = 'CLIENT_ID'
const clientSecret = 'CLIENT_SECRET'

if(process.argv.length <= 2) {
  console.error('You must specify access_token')
  return
}
const accessToken = process.argv[2]

const rpc = new DiscordRPC.Client({ transport: 'ipc' });

function startWebServer() {
  const app = express()
  const port = 3000

  app.get('/', (req, res) => {
    rpc.getVoiceSettings().then((e) => {
      return rpc.setVoiceSettings({mute: !e.mute})
    }).then(() => {
      res.sendStatus(200)
    })
  })

  app.listen(port, '0.0.0.0', () => {
    console.log(`Discord Muter listening at http://localhost:${port}`)
  })

}

rpc.on('ready', () => {
  startWebServer()
});

rpc.login({
  clientId,
  scopes: ['rpc', 'rpc.api', 'identify'],
  accessToken
}).catch(console.error);

やってみよう

Discordのアプリを開いて,ボイスチャットに入っておきます.
$ node index.js {アクセストークン}でサーバーを起動します.
その状態で,普通に,PCのブラウザから,http://localhost:3000/にアクセスすると,ミュートになります.
もう一度アクセスでミュート解除です.

私はTaskerでウィジェット化しています.

他にもRPCにはいろいろなAPIが用意されていそうなので,時間があるときに探してみたいと思います!!

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