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

Node.js入門編

Node.jsとは? フロントエンドエンジニアですが、技術の幅を広げる為、JavaScript力をあげる為にNode.jsをやろうと思い、まずは概要を簡単ですがまとめました。ノンブロッキングI/Oとか難しい部分は追って学んで行こうと思います。 Node.jsはサーバーサイドのJavaScript実行環境と言われてますが、これだけだとピンとこないですね。さらに詳しく説明すると、 Node.jsは「V8」というJavaScript実行エンジンで作られてる。 (V8はGoogleが開発しているオープンソースのJavaScript実行エンジンです。V8はNode.jsに限らず、GoogleChromeでも採用されています。) つまり、Node.js環境をサーバー上に作る → サーバーサイドでJavaScriptを実行できる → JavaScriptでサーバーサイドを実装できるという事です。 もちろんNode.js固有の文法やAPIが沢山あるので、フロントエンドのJS力だけで良いという訳ではないですが、慣れ親しんだJSでサーバーも作れるのは全く違う言語を覚えるよりはとっつきやすいかもしれません。(ただ本気でNode.jsを習得するのと他のサーバー言語を習得するコストはあまり変わらないとも言われてます。。) ちなみに、他ブラウザのJavaScript実行エンジンは、 ・Firefox: SpiderMonkey ・Safari: JavaScriptCore ・MicrosoftEdge: Chakra/V8 らしいです。 クライアントの開発環境としても使われる ReactやVueなどの開発に使われるwebpack-dev-serverを使ってローカルサーバーを立てるのにNode.jsは使われています。 npmとは? Node Package Managerの略で、Node.jsの実装はnpmを活用して行ないます。 npmに登録されてるパッケージであれば(=Node.jsパッケージとして流通してる)、npmを使って簡単にインストールできます。npmでインストールしたパッケージはnode_modules配下に入りimport, requireで使えます。 「パッケージ」というのはライブラリやフレームワークのことで、わざわざライブラリのLPに行ってダウンロードして、プロジェクトディレクトリに置いて、なんて事しなくてもnpmコマンドを使えば一発で取り込めると言うことです。 yarn: Facebook製のパッケージマネージャー npmでインストールする各種パッケージは本体はリモートにあるので、それを取得してインストールするクライアントはnpmじゃなくてもいい。yarnは高速で信頼性が高く、依存関係も安全に保てる。 余談: 以前業務でフロントのプロジェクトの中に組み込まれていた結構大きめな処理を外に出して、npmに登録し、外部ライブラリとして取り込んで使う運用になった事がありました。 Express Expressは、Node.jsで一番人気なフレームワークです。 プレーンなNode.jsだと大変な開発を楽にしてくれる優れものです。 以下、基本手順のコードだけを抜粋して紹介します。 ・Expressオブジェクトの用意 ・appオブジェクトの作成 ・ルートの設定 ・待ち受け開始 //Expressオブジェクト、appオブジェクトの用意 import * as express from "express"; const app = express(); //第1引数のアドレスにアクセスした(リクエストが来た)時に、第2引数の関数を呼ぶ app.use('/users', users) ルートの設定は、routesディレクトリに各ルートのJSファイルを用意して設定します。 const router = express.Router(); router.get('/', (req, res) => { //この中で処理をして、最終的に何かしらのレスポンスをする //res.send()であれば、引数の値をレスポンスとして返す const responseData = "Welcome to Express"; res.send(responseData); }) app.listen(3000) これでプログラムを実行して、http://localhost:3000にアクセスすると「Welcome to Express」と表示されます。 Express Generator Expressでアプリケーションを作っても、必要なファイル、モジュールなどは全て自前で用意しないといけないのですが、「基本セット」を最初から用意してくれるライブラリがExpress Generatorです。 Reactでいうところのcreate-react-appみたいなものかと思います。個人開発や学習の為なら間違いなくこれを使ってやるべきですね。 まとめ 本編では、あくまでも基本的な概念やExpressの基本のまとめです。 次は実際に定番のToDoアプリを作ってデプロイまでやってみますので、そこでは詳しいコードを交えた記事にしたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】分割代入について

配列やオブジェクトの値を分割して代入したいときに有効 配列 sample.js const array = [1, 2, 3]; // e0...array[0]...e1...array[1]...e2...array[2]............ const [e0, e1, e2] = array; console.log(e0)// 1 console.log(e1)// 2 console.log(e2)// 3 オブジェクト オブジェクトを変数に代入するときに分割して代入することができる sample.js const obj = {a: 10, b: 20, c: 30}; const {a, c} = obj; console.log(a); // 10 console.log(c); // 30 動作確認 docker run -it --rm node:lts-alpine sh /# vi test.js # ファイルをコピペ /# node test.js
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今まで起きたエラーを管理するアプリ作ってみた

フロントをReact、サーバーサイドをNode、Expressで作成しました。 DBとしてFirebase Cloud Firestoreを使用し、フロントをFirebase Hosting、サーバーをHerokuにデプロイしました。 作ったアプリについて 私は現在エンジニアとしてインターンを2年間やっており、エラーが出たときに「このエラーどっかで見たなぁ」みたいなことが最初の頃よくありました。 今回はこのようなことを解消するためのアプリを作成しました。 使用方法 起きたエラーを入力 カテゴリーを選択(React,Nodeなど) 解決できているならば参考になったURLを記入 メモを書く という流れになります。 今までに起きたエラーを蓄積していくことで、もし同じエラーが起きた場合は、エラーを入力した際に知らせてくれて再び解決策を探す作業が省くことができます。 こちらが作ったアプリ( Error Manager )になりますが 現在はサインアップを実装しておらず、私だけが使えるテスト段階です。 詰まったところ Reactでのログイン認証 色々と調べたところ、しっかりとしたアプリならばセキュリティを考慮して自分でログイン認証を作成するべきではなく、Auth0などのサービスを使用したほうがいいというのが結論でした。 ただ、今回のような小規模な重要な情報を保持しないアプリであれば、LocalStorageやCookieを使って実装してもよいという意見もあり、CookieとFirebase Authenticationで実装しました。 Firebase Authenticationでログイン認証を行い、ログインしたらCookieにID、Passwordを保持し、ログアウトしたらCookieのID、Passwordを削除するという方法になります。 Firebase Authenticationのログイン認証の実装に関しては公式のドキュメントがわかりやすいので詳しい設定はこちらを参考に。 サインイン画面でSubmitボタンを押すと、以下のsigninFunc()が動き、 signInWithEmailAndPasswordでFirebase Authenticationの認証が成功したらCookies.setでemail、password、uid(Firebase Authentication側で勝手に割り振られるID)をCookieに書き込みます。 認証失敗したらEmailもしくはPasswordが間違っている可能性があることをユーザーに知らせます。 Cookieを操作するライブラリはjs-cookieを使用しました。 signin.js const signinFunc = () => { const email = document.getElementById("email").value const password = document.getElementById("password").value firebase.auth().signInWithEmailAndPassword(email, password) .then((user) => { setOpenErr(false) setOpenSuc(true) Cookies.set("email",email,{"expires":7}) Cookies.set("password",password,{"expires":7}) Cookies.set("uid",user.user.uid,{"expires":7}) document.location = "/" }) .catch((error) => { setOpenErr(true) var errorMessage = error.message; console.log(errorMessage) }); } ログイン認証後は、Cookieにあるemail、password、uidを使ってホーム画面に遷移する際に認証します。 App.js import './App.css'; import SignIn from './pages/signIn'; import SignUp from './pages/signUp'; import Main from './pages/main' import { BrowserRouter, Route, Switch } from 'react-router-dom'; import Auth from './components/Auth'; function App() { return ( <BrowserRouter> <Switch> <Route path="/signin" component={SignIn}/> <Auth> <Switch> <Route path="/" exact component={Main} /> </Switch> </Auth> </Switch> </BrowserRouter> ); } export default App; User.js import Cookies from 'js-cookie' import firebase from '../firebase/firebase' export function isLoggedIn(){ const email = Cookies.get("email") const password = Cookies.get("password") if(!(email && password)) return false const isLogin = firebase.auth().signInWithEmailAndPassword(email, password) .then((user) => true) .catch((error) => { const errorMessage = error.message; return false }); return isLogin; } export function logoutFunc(){ Cookies.remove("email") Cookies.remove("password") Cookies.remove("uid") document.location = "/signin" } ログインしていないとホーム画面に遷移できないようにする方法はこちらの記事を参考にしました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Lambda関数で「AWS-SDK」をローカル環境でのみ読み込み、本番デプロイでは除外する方法

結論 こうすればいい cd ~ # グローバルパッケージのインストール先確認 npm root -g # グローバルインストール npm install -g aws-sdk # グローバルパッケージが本当にインストールされたかを確認する npm list -g --depth=0 # ローカルパッケージとして読み込みたいプロジェクトディレクトリに移動する cd ~/environment/myLambdaProjectName # グローバルパッケージとローカルパッケージのシンボリックリンクを作成する npm link aws-sdk # ローカルパッケージとして読み込まれているかを確認する npm list --depth=0 あとはこれをZIPファイルにまとめてデプロイするなり、なんなりと 何がしたいか 私が開発したあるプロジェクトは、DynamoDBからレコードを取り出して、 RdsDBにINSERTするという行為をLambda関数で実現するというものでした。 本番環境のLambdaは最初からAWS-SDKパッケージが用意されているので、 ローカルパッケージとしてZIPファイルに含める必要はありません。ファイルサイズが増えるだけです。 しかし、ローカル環境(Cloud9)にAWS-SDKパッケージがないので、 今までは npm install aws-sdk して毎回AWS-SDKをローカルインストールして、 本番デプロイ前に手動でaws-sdkディレクトリを削除するという何ともアレな運用をしていました。 何か、ローカル環境だけAWS-SDKを読み込ませて、 本番デプロイ時は手動削除しないで良い方法を探したら、上の方法を見つけた次第です。 他に良い方法をご存じの方がいましたら、教えてください。 追記 Cloud9環境で、ローカルからLambdaにデプロイする場合は、次の手順で行います cd ~/environment/myLambdaProjectName zip --symlinks -r hoge.zip . 左サイドバー > AWS > AWS: Explorer > Asia Pacific (Tokyo) > Lambda > {myFunctionName} アップロードしたいLambda関数名を右クリック、Upload Lambda > ZIP Archiveを選択、 先ほどZIP圧縮したファイルを選択して、OKボタンを押すと、デプロイできます うまくいけば、画面右上にちっさく Successfully uploaded Lambda function {myFunctionName} が表示されます 本当にAWS-SDKが除外されてアップロードされているかは、以下の手順で確認できます Lambdaコンソール画面に移動 Lambda > 関数 > {myFunctionName} に移動 画面右上、アクション > 関数のエクスポート > デプロイパッケージのダウンロード ダウンロードしたZIPファイルを開き、node_modulesディレクトリ内にaws-sdkディレクトリがないことを確認する Upload Lambda > Directory を使うことでもデプロイはできますが、 そちらはシンボリックリンクを辿って、 実ファイルを含んだ状態でアップロードしてしまうので、 ファイルサイズを抑えることができません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NestJSを触りながら学ぶ(TodoAPI作成)

NestJSとは Nest (NestJS) is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with and fully supports TypeScript (yet still enables developers to code in pure JavaScript) and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Reactive Programming). Under the hood, Nest makes use of robust HTTP Server frameworks like Express (the default) and optionally can be configured to use Fastify as well! Nest provides a level of abstraction above these common Node.js frameworks (Express/Fastify), but also exposes their APIs directly to the developer. This gives developers the freedom to use the myriad of third-party modules which are available for the underlying platform. Node.jsのバックエンドフレームワークです。 デフォルトでExpress(Node.jsのWebアプリケーションフレームワーク)が内部で使用されていますので、Expressの技術を流用できます。 設定変更でFastify(軽量なNode.jsフレームワーク)を使用することも可能です。 またTypescriptで構成されているので、フロントエンドの方でもすんなり入っていけると思われます。 NestJSのアーキテクチャ NestJSは下図のような構成例で開発することができます。 構成例 Module 依存関係の管理を行う。 ルートモジュール(上図でいうAppModule)が開始点となる。 Controller クライアントからのリクエストを処理し、応答を返す。 上図の構成だと実処理はServiceが担っていることが多く、リソースを取得するエンドポイントだけ定義している。 Service NestJSにおけるプロバイダーの一種。依存性の注入に利用される。 上図の構成だとControllerに機能提供している。 環境 Node.js v12.19.1 PostgreSQL 12.5 macOS Catalina インストール 以下のコマンドでNest CLIをインストールし、プロジェクトを作成します。 $ npm i -g @nestjs/cli $ nest new TodoApp    // nest new [プロジェクト名] ⚡ We will scaffold your app in a few seconds.. CREATE todo-app/.eslintrc.js (630 bytes) CREATE todo-app/.prettierrc (51 bytes) CREATE todo-app/README.md (3339 bytes) CREATE todo-app/nest-cli.json (64 bytes) CREATE todo-app/package.json (1962 bytes) CREATE todo-app/tsconfig.build.json (97 bytes) CREATE todo-app/tsconfig.json (339 bytes) CREATE todo-app/src/app.controller.spec.ts (617 bytes) CREATE todo-app/src/app.controller.ts (274 bytes) CREATE todo-app/src/app.module.ts (249 bytes) CREATE todo-app/src/app.service.ts (142 bytes) CREATE todo-app/src/main.ts (208 bytes) CREATE todo-app/test/app.e2e-spec.ts (630 bytes) CREATE todo-app/test/jest-e2e.json (183 bytes) ? Which package manager would you ❤️ to use? (Use arrow keys) ❯ npm yarn ///// npm か yarnか選びます(今回はyarnを選んでる) //// ▹▸▹▹▹ Installation in progress... ☕ ? Successfully created project todo-app ? Get started with the following commands: $ cd todo-app $ yarn run start Thanks for installing Nest ? Please consider donating to our open collective to help us maintain this package. ? Donate: https://opencollective.com/nest 出来上がる構成は下記のようになります。 todo-app ├── .eslintrc.js // ESLintの設定ファイル ├── .git // gitリポジトリのスケルトンディレクトリ ├── .gitignore // git管理除外設定ファイル ├── .prettierrc // Prettierの設定ファイル ├── README.md // NestJSのREADME ├── dist // ビルド結果出力先 ├── nest-cli.json // プロジェクトを整理、構築、デプロイするために必要なメタデータが書いてあるファイル(Monorepo) ├── node_modules // プロジェクトで利用する npm ライブラリの配置先 ├── package.json // npm の設定ファイル ├── src // 実装していくコードの配置先 ├── test // E2Eテストコード配置先 ├── tsconfig.build.json // tsconfig.jsonの分割ファイル(デフォルトはトランスパイ対象外ディレクトリが書いてある) ├── tsconfig.json // TypeScript を JavaScript にトランスパイルための設定情報ファイル └── yarn.lock // yarnの構成管理ファイル(npmだとpackage-lock.jsonが生成されてます) 動作確認だけします。 $ cd todo-app $ yarn run start yarn run v1.22.5 $ nest start [Nest] 132 - 11/20/2020, 1:52:37 PM [NestFactory] Starting Nest application... [Nest] 132 - 11/20/2020, 1:52:37 PM [InstanceLoader] AppModule dependencies initialized +56ms [Nest] 132 - 11/20/2020, 1:52:37 PM [RoutesResolver] AppController {}: +39ms [Nest] 132 - 11/20/2020, 1:52:37 PM [RouterExplorer] Mapped {, GET} route +19ms [Nest] 132 - 11/20/2020, 1:52:38 PM [NestApplication] Nest application successfully started +7ms Nest application successfullyが出力されたらブラウザでhttp://localhost:3000/を開きHello World!が表示されていたらOK。 Ctrl + Cで終了できます。 準備 データベース作成 作成方法はコマンド、クライアントアプリ(pgAdminなど)の使用、どちらでも構いません。 コマンド postgres=# create database todoapp; CREATE DATABASE SQLクライアントアプリ pgAdmin DBeaver ファイル削除 srcディレクトリの直下は以下のファイルが配置されています。 今回必要ないものは削ってしまいます。 app.controller.spec.ts 削除対象。AppControllerのユニットテスト用ファイル。 app.controller.ts 削除対象。デフォルトコントローラ。 app.module.ts ルートモジュール。 app.service.ts 削除対象。デフォルトプロバイダ(サービス)。 main.ts NestJSアプリケーションインスタンスを作成するエントリファイル。 main.tsとapp.module.tsだけ残ります。 削除ついでにapp.module.tsも修正しておきます。 app.module.ts import { Module } from '@nestjs/common'; @Module({ imports: [], }) export class AppModule {} // AppController と AppService をファイル内から削除 必要パッケージインストール npm なら npm install [パッケージ名] --save yarn なら yarn add [パッケージ名] で各種インストールします。 パッケージ 用途 @nestjs/typeorm TypeORM統合(NestJS専用パッケージ) typeorm TypeORM使用 pg PostgreSQL使用 @nestjs/config 環境変数使用 class-validator バリデーション用(パイプ機能で使用) class-transformer オブジェクト変換用(パイプ機能で使用) Module作成 構成 今回は下図のようなシンプルな構成で作っていこうと思います。 CLI(Genarate Module) CLIを使用してModuleを作成します。 nest g module [module名]で自動生成されます。 $ nest g module tasks CREATE src/tasks/tasks.module.ts (82 bytes) UPDATE src/app.module.ts (312 bytes) 中身は以下のように、ほとんど空のような状態です。 tasks/tasks.module.ts import { Module } from '@nestjs/common'; @Module({}) export class TasksModule {} Controller作成 CLI(Genarate Controller) こちらもCLIを使用してControllerを作成します。 nest g controller [controller名]で生成されます。 同時にテスト用のファイルも自動生成されます。今回は使用しないので--no-specオプションを追加して生成しないようにします。 $ nest g controller tasks --no-spec CREATE src/tasks/tasks.controller.ts (99 bytes) UPDATE src/tasks/tasks.module.ts (170 bytes) この時点でtasks.module.tsに自動でControllerが追記されています。 tasks/tasks.module.ts import { Module } from '@nestjs/common'; import { TasksController } from './tasks.controller'; // 自動追加 @Module({ controllers: [TasksController] // 自動追加 }) export class TasksModule {} ルーティング 各リクエストのルートマッピングは以下のように構成します。 URL HTTP Method Decorator Contents /tasks GET getTasks @Get() 登録されているタスク取得 /tasks/[id] GET getTaskById @Get(/:id) [id]のタスク取得 /tasks POST createTask @Podt() 新規タスク登録 /tasks/[id] DELETE deleteTask @Delete(/:id) 登録されている[id]のタスク削除 /tasks/[id] PATCH updateTaskStatus @Patch(/:id) 登録されている[id]のタスク更新 HTTPプロトコルの参考リンク コントローラ内のメソッドにデコレータを付与してあげることで、ハンドラとしてマッピングします。 Controller修正 上記の構成で作成します。 tasks/tasks.controller.ts import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post } from '@nestjs/common'; @Controller('tasks') export class TasksController { @Get() getTasks() { return "getTasks Success!" } @Get('/:id') getTaskById( @Param('id', ParseIntPipe) id: number) { return `getTaskById Success! Parameter [id:${id}]` } @Post() createTask( @Body('title') title: string, @Body('description') description: string) { return `createTask Success! Prameter [title:${title}, descritpion:${description}]` } @Delete('/:id') deleteTask( @Param('id', ParseIntPipe) id: number) { return `deleteTask Success! Prameter [id:${id}]` } @Patch('/:id') updateTask( @Param('id', ParseIntPipe) id: number, @Body('status') status: string ) { return `updateTask Success! Prameter [id:${id}, status:${status}]` } } @Param()や@Body()はHTTPリクエストを取得するためのデコレータです。 基本はExpressのリクエストオブジェクトのプロパティに沿っています。(Express Application Request) ParseIntPipeはパイプという機能の1つです。 コントローラのメソッドに値が引き渡される前に変換、もしくは検証を行います。 @Param('id', ParseIntPipe)ではidを数値型へと変換します。(変換できなかった場合は例外をスローします) 動作確認 早速確認しましょう。 yarn run start:devでファイル更新があるたびに自動的に再起動してくれるので、開発中はそちらでNestJSを起動するのがオススメです。 APIの確認は素直にツールを使用した方が手間がないです。 参考: Postman Restlet Client もちろんcurlでも可能。 $ curl -X GET http://localhost:3000/tasks getTasks Success! $ curl -X GET http://localhost:3000/tasks/1 getTaskById Success! Parameter [id:1] $ curl -X POST http://localhost:3000/tasks -d 'title=TEST' -d 'description=NestJS' createTask Success! Prameter [title:TEST, descritpion:NestJS] $ curl -X PATCH http://localhost:3000/tasks/1 -d 'status=DONE' updateTask Success! Prameter [id:1, status:DONE] $ curl -X DELETE http://localhost:3000/tasks/1 deleteTask Success! Prameter [id:1] // パイプで変換できない場合、いい感じに返してくれる(内容変更可能) $ curl -X GET http://localhost:3000/tasks/aaa {"statusCode":400,"message":"Validation failed (numeric string is expected)","error":"Bad Request"} リクエストオブジェクトから値が取得できていることが分かると思います。 DTO作成 値を渡す際のバリデーションを有効するためにDTOを定義していきます。 tasks/dto/task-property.dto.ts import { IsNotEmpty } from "class-validator"; export class TaskPropertyDto { @IsNotEmpty() title: string; @IsNotEmpty() description: string; } デコレータの@IsNotEmptyは値に"",null,undefinedを受け入れません。 Pipe作成 statusに対するパイプ機能を実装します。 tasks/pipe/task-status.pipe.ts import { BadRequestException, PipeTransform } from "@nestjs/common"; export class TaskStatusPipe implements PipeTransform { readonly allowStatus = [ 'OPEN', 'PROGRESS', 'DONE' ]; transform(value: any) { value = value.toUpperCase(); if(!this.isStatusValid(value)) { throw new BadRequestException(); } return value; } private isStatusValid(status: any) { const result = this.allowStatus.indexOf(status); return result !== -1; } } PipeTransformを継承することによって検証機能をもつパイプを自ら作成することができます。 上記はstatusが'OPEN','PROGRESS','DONE'のいづれかでないとエラーを返しています。 Controller修正(DTO、Pipe追加) tasks/tasks.controller.ts import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, UsePipes, ValidationPipe } from '@nestjs/common'; import { TaskPropertyDto } from './dto/task-property.dto'; import { TaskStatusPipe } from './pipe/task-status.pipe'; @Controller('tasks') export class TasksController { @Get() getTasks() { return "getTasks Success!" } @Get('/:id') getTaskById( @Param('id', ParseIntPipe) id: number) { return `getTaskById Success! Parameter [id:${id}]` } @Post() @UsePipes(ValidationPipe) createTask( @Body() taskPropertyDto: TaskPropertyDto) { const { title, description } = taskPropertyDto return `createTask Success! Prameter [title:${title}, descritpion:${description}]` } @Delete('/:id') deleteTask( @Param('id', ParseIntPipe) id: number) { return `deleteTask Success! Prameter [id:${id}]` } @Patch('/:id') updateTask( @Param('id', ParseIntPipe) id: number, @Body('status',TaskStatusPipe) status: string ) { return `updateTask Success! Prameter [id:${id}, status:${status}]` } } @UsePipesを付与したメソッドはバリデーションパイプ(今回でいうとTaskPropertyDtoで定義した値の空検証)が有効になります。 updateTaskで作成したパイプを定義していますが、この場合ですとstatusの値にだけおよびます。 Service作成 CLI(Genarate Service) CLIでServiceを作成します。 nest g service [service名]で生成されます。 今回はテストファイルも作ってみましょう。 $ nest g service tasks CREATE src/tasks/tasks.service.spec.ts (453 bytes) CREATE src/tasks/tasks.service.ts (89 bytes) UPDATE src/tasks/tasks.module.ts (247 bytes) tasks.module.tsに自動で追記されてます。 tasks/tasks.module.ts import { Module } from '@nestjs/common'; import { TasksController } from './tasks.controller'; import { TasksService } from './tasks.service'; // 自動追加 @Module({ controllers: [TasksController], providers: [TasksService] // 自動追加 }) export class TasksModule {} TypeORMの準備 Service実装の前に、DBとのやりとりのためにTypeORMの設定を行っておきます。 接続設定 DBとの接続を設定します。 app.module.tsに下記を追加します。 app.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; // 追加 import { TasksModule } from './tasks/tasks.module'; @Module({ imports: [ TasksModule, // importsに追加 TypeOrmModule.forRoot({ type: 'postgres', // DBの種類 port: 5432, // 使用ポート database: 'todoapp', // データベース名 host: 'localhost', // DBホスト名 username: 'root', // DBユーザ名 password: 'root', // DBパスワード synchronize: true, // モデル同期(trueで同期) entities: [__dirname + '/**/*.entity.{js,ts}'], // ロードするエンティティ }) ], }) export class AppModule {} この状態でyarn run startをしてみましょう。 [Nest] 118 - 11/29/2020, 6:04:30 AM [NestFactory] Starting Nest application... [Nest] 118 - 11/29/2020, 6:04:31 AM [InstanceLoader] TypeOrmModule dependencies initialized +933ms [Nest] 118 - 11/29/2020, 6:04:31 AM [InstanceLoader] AppModule dependencies initialized +4ms [Nest] 118 - 11/29/2020, 6:04:31 AM [InstanceLoader] TasksModule dependencies initialized +3ms [Nest] 118 - 11/29/2020, 6:04:32 AM [InstanceLoader] TypeOrmCoreModule dependencies initialized +1270ms [Nest] 118 - 11/29/2020, 6:04:32 AM [RoutesResolver] TasksController {/tasks}: +3ms [Nest] 118 - 11/29/2020, 6:04:32 AM [RouterExplorer] Mapped {/tasks, GET} route +3ms [Nest] 118 - 11/29/2020, 6:04:32 AM [RouterExplorer] Mapped {/tasks/:id, GET} route +4ms [Nest] 118 - 11/29/2020, 6:04:32 AM [RouterExplorer] Mapped {/tasks, POST} route +5ms [Nest] 118 - 11/29/2020, 6:04:32 AM [RouterExplorer] Mapped {/tasks/:id, DELETE} route +4ms [Nest] 118 - 11/29/2020, 6:04:32 AM [RouterExplorer] Mapped {/tasks/:id, PATCH} route +2ms [Nest] 118 - 11/29/2020, 6:04:32 AM [NestApplication] Nest application successfully started +9ms エラーが出なければ接続成功です。 Entitiyの作成 以下のようなテーブル内容で作成しようと思います。 Task id: number title: string description: string status: string 新規にtask.entity.tsを作成します。 TypeORMについての説明は省略させて頂きます。 参考: TypeORM(github) tasks/tasks.entity.ts import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity() export class Task extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() title: string; @Column() description: string; @Column() status: string; } yarn run startでNestJSを起動してDBの中を見てみます。 (下記はコマンドで確認してますが、確認できればなんでもよいです。) todoapp=# \d List of relations Schema | Name | Type | Owner --------+-------------+----------+------- public | task | table | root public | task_id_seq | sequence | root (2 rows) todoapp=# \d task Table "public.task" Column | Type | Collation | Nullable | Default -------------+-------------------+-----------+----------+---------------------------------- id | integer | | not null | nextval('task_id_seq'::regclass) title | character varying | | not null | description | character varying | | not null | status | character varying | | not null | Indexes: "PK_fb213f79ee45060ba925ecd576e" PRIMARY KEY, btree (id) ちゃんと同期がとれてますね。 環境毎での設定変更 envファイル 開発時点ではこれでいいのですが、本番環境では同期するとエライ目にあうので、環境変数を読み込むように変更します。 プロジェクトのルートディレクトリ直下に.envディレクトリを新規に作成し、各環境毎の構成ファイルを格納します。 .env/default.env API_PORT=3000 DB_PORT=5432 DB_NAME=todoapp DB_HOSTNAME=localhost DB_USERNAME=root DB_PASSWORD=root .env/development.env DB_SYNC=true .env/production.env DB_SYNC=false 環境毎にdevlopment.envとproduction.envを切り替えて使います(default.envは他envファイルで上書き可能な共通定義を書いてます) TypeORMのConfigService この定義を読み込むTypeORMのConfigServiceを作成します。 srcディレクトリにconfigディレクトリを作成し格納します。 config/typeorm-config.service.ts import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { TypeOrmModuleOptions, TypeOrmOptionsFactory } from "@nestjs/typeorm"; @Injectable() export class TypeOrmConfigService implements TypeOrmOptionsFactory { createTypeOrmOptions(): TypeOrmModuleOptions { const configService = new ConfigService(); return { type: 'postgres', host: configService.get<string>('DB_HOSTNAME'), port: configService.get<number>('DB_PORT'), username: configService.get<string>('DB_USERNAME'), password: configService.get<string>('DB_PASSWORD'), database: configService.get<string>('DB_NAME'), entities: [__dirname + '/../**/*.entity.{js,ts}'], synchronize: this.strToBoolean(configService.get<string>('DB_SYNC', 'false')) }; } // get<boolean>が上手く変換してくれないため泣く泣く対応 private strToBoolean(boolStr:string):boolean { switch(boolStr.toLowerCase().trim()) { case "true": case "yes": case "1": return true; case "false": case "no": case "0": case null: return false; default: return boolStr as unknown as boolean } } } ConfigServiceのgetメソッドで環境変数を取得できます。 さきほどapp.module.tsに直接記述していたオプション達をここにまとめておきます。 AppModule修正 app.module.ts import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmConfigService } from './config/typeorm-config.service'; import { TasksModule } from './tasks/tasks.module'; @Module({ imports: [ /** env読み込み * 環境変数NODE_ENVの値によって読み込むファイルを切り替える。 * default.envは後続で呼ばれる。同じ変数がある場合は先に定義されているものが優先される。 */ ConfigModule.forRoot({ envFilePath: [`.env/${process.env.NODE_ENV}.env`,'.env/default.env'], isGlobal: true, }), // TypeORMの設定を非同期取得に変更 TypeOrmModule.forRootAsync({ imports: [ConfigModule], useClass: TypeOrmConfigService, }), TasksModule, ], }) export class AppModule {} これで環境ごとに接続情報を書き換える手間を省けます。 動作確認 分かりやすくコンソールに表示されるようmain.tsを書き換えましょう(ついでlistenポートもenvを参照するようにしちゃいましょう) main.ts import { ConfigService } from '@nestjs/config'; // 追加 import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); const configService = new ConfigService(); // 追加 const sync = configService.get('DB_SYNC'); // 追加 console.log(`TypeORM synchronize is [ ${sync} ]`); // 追加 const port = configService.get('API_PORT'); // 追加 await app.listen(port); // 3000をportに変更 } bootstrap(); NODE_ENVを設定して起動してみます。 // dev $ NODE_ENV=development yarn run start yarn run v1.22.5 $ nest start [Nest] 195 - 11/29/2020, 3:06:23 PM [NestFactory] Starting Nest application... ~~~ 略 ~~~~ [Nest] 195 - 11/29/2020, 3:06:24 PM [InstanceLoader] TasksModule dependencies initialized +1ms [Nest] 195 - 11/29/2020, 3:06:25 PM [InstanceLoader] TypeOrmCoreModule dependencies initialized +560ms TypeORM synchronize is [ true ] ~~~ 略 ~~~~ // prod $ NODE_ENV=production yarn run start yarn run v1.22.5 $ nest start [Nest] 195 - 11/29/2020, 3:06:23 PM [NestFactory] Starting Nest application... ~~~ 略 ~~~~ TypeORM synchronize is [ false ] ~~~ 略 ~~~~ // ランタイム環境に既に環境変数が存在する場合、そちらが優先される $ NODE_ENV=development DB_SYNC=false yarn run start yarn run v1.22.5 $ nest start [Nest] 195 - 11/29/2020, 3:06:23 PM [NestFactory] Starting Nest application... ~~~ 略 ~~~~ TypeORM synchronize is [ false ] ~~~ 略 ~~~~ (ここまで書いてなんだが、node-config使った方が綺麗にまとまりそうですね・・・) Serviceの修正 tasks/tasks.service.ts import { Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { TaskPropertyDto } from './dto/task-property.dto'; import { Task } from './task.entity'; @Injectable() export class TasksService { constructor( @InjectRepository(Task) private taskRepository: Repository<Task>, ) { } async getTasks(): Promise<Task[]> { return this.taskRepository.find(); } async getTaskById(id: number): Promise<Task> { const found = await this.taskRepository.findOne(id); if (!found) { throw new NotFoundException(); } return found; } async createTask( taskPropertyDto: TaskPropertyDto ): Promise<Task> { const { title, description } = taskPropertyDto; const task = new Task(); task.title = title; task.description = description; task.status = 'OPEN'; try { await this.taskRepository.save(task); } catch (error) { throw new InternalServerErrorException(); } return task; } async deleteTask(id: number): Promise<void> { const result = await this.taskRepository.delete(id); if (result.affected === 0) { throw new NotFoundException(); } } async updateTask( id: number, status: string): Promise<Task> { const task = await this.getTaskById(id); task.status = status; await this.taskRepository.save(task); return task; } } Controllerから受け取った値で実処理するよう構成しています。 あとはControllerのファイルを修正すれば完成なのですが、Service作成時にテストファイルを作成したので、テストを行っていきましょう。 テスト作成 テストはJestがデフォルトになっています。 NestJSはテストツールに制限があるわけでないので、お好みでよいようです。 今回はデフォルトのJestでいきます。 tasks/tasks.service.spec.ts import { NotFoundException } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; import { Task } from './task.entity'; import { TasksService } from './tasks.service'; const mockRepository = () => ({ find: jest.fn(), findOne: jest.fn(), save: jest.fn(), delete: jest.fn(), }); describe('TasksService', () => { let tasksService: TasksService; let taskRepository; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ TasksService, { provide: getRepositoryToken(Task), useFactory: mockRepository } ] }).compile(); tasksService = await module.get<TasksService>(TasksService); taskRepository = await module.get(getRepositoryToken(Task)); }); describe('getTasks', () => { it('get all tasks', async () => { taskRepository.find.mockResolvedValue('mockTask'); expect(taskRepository.find).not.toHaveBeenCalled(); const result = await tasksService.getTasks() expect(taskRepository.find).toHaveBeenCalled(); expect(result).toEqual('mockTask'); }); }); describe('getTaskById', () => { it('find success', async () => { const mockTask = { title: 'mockTitle', description: 'mockDesc' }; taskRepository.findOne.mockResolvedValue(mockTask); expect(taskRepository.findOne).not.toHaveBeenCalled(); const mockId: number = 1; const result = await tasksService.getTaskById(mockId); expect(taskRepository.findOne).toHaveBeenCalled(); expect(result).toEqual(mockTask); }); it('task is not found', async () => { const mockId: number = 1; taskRepository.findOne.mockResolvedValue(null); expect(tasksService.getTaskById(mockId)).rejects.toThrow(NotFoundException); }); }); describe('createTask', () => { it('insert task', async () => { const mockTask = { title: 'mockTitle', description: 'mockDesc' }; taskRepository.save.mockResolvedValue(mockTask); expect(taskRepository.save).not.toHaveBeenCalled(); const result = await tasksService.createTask(mockTask.title, mockTask.description); expect(taskRepository.save).toHaveBeenCalled(); expect(result).toEqual({ title: mockTask.title, description: mockTask.description, status: 'OPEN' }); }); }); describe('deleteTask', () => { it('delete task', async () => { taskRepository.delete.mockResolvedValue({ affected: 1 }); expect(taskRepository.delete).not.toHaveBeenCalled(); const mockId: number = 1; await tasksService.deleteTask(mockId); expect(taskRepository.delete).toHaveBeenCalledWith(mockId); }); it('delete error', async () => { taskRepository.delete.mockResolvedValue({ affected: 0 }); const mockId: number = 1; expect(tasksService.deleteTask(mockId)).rejects.toThrow(NotFoundException); }); }); describe('updateTask', () => { it('update status', async () => { const mockStatus = 'DONE'; tasksService.getTaskById = jest.fn().mockResolvedValue({ status: 'OPEN' }); expect(tasksService.getTaskById).not.toHaveBeenCalled(); const mockId: number = 1; const result = await tasksService.updateTask(mockId, mockStatus); expect(tasksService.getTaskById).toHaveBeenCalled(); expect(taskRepository.save).toHaveBeenCalled(); expect(result.status).toEqual(mockStatus); }); }); }); beforeEachで呼ばれているTest.createTestingModuleはモックやオーバーライドなど、クラスインスタンスの管理を容易にしてくれるフックの機能があります。 今回はDBのアクセスはモックにするので、Repositoryクラスのfindやsaveはオーバライドしています。 テスト実行 yarn run testで実行しましょう。(yarn run test:watchでファイルが更新する度テストをしてくれることも出来ます) Watch Usage: Press w to show more. PASS src/tasks/tasks.service.spec.ts (21.055 s) TasksService getTasks ✓ get all tasks (9 ms) getTaskById ✓ find success (5 ms) ✓ task is not found (19 ms) createTask ✓ insert task (6 ms) deleteTask ✓ delete task (5 ms) ✓ delete error (5 ms) updateTask ✓ update status (5 ms) Test Suites: 1 passed, 1 total Tests: 7 passed, 7 total Snapshots: 0 total Time: 21.135 s, estimated 22 s なんだが良く分からないけどエラーがないのでヨシ!(テストムズカシイ・・・) Module & Controller修正 ControllerはServiceに値を渡すよう修正しましょう。 tasks/task.controller.ts import { Body, Controller, Delete, Get, Param, ParseIntPipe, Patch, Post, UsePipes, ValidationPipe } from '@nestjs/common'; import { TaskPropertyDto } from './dto/task-property.dto'; import { TaskStatusPipe } from './pipe/task-status.pipe'; import { Task } from './task.entity'; import { TasksService } from './tasks.service'; @Controller('tasks') export class TasksController { constructor( private tasksService: TasksService ) {} @Get() getTasks(): Promise<Task[]> { return this.tasksService.getTasks(); } @Get('/:id') getTaskById( @Param('id', ParseIntPipe) id: number): Promise<Task> { return this.tasksService.getTaskById(id); } @Post() @UsePipes(ValidationPipe) createTask( @Body() taskPropertyDto: TaskPropertyDto ): Promise<Task> { return this.tasksService.createTask(taskPropertyDto); } @Delete('/:id') deleteTask( @Param('id', ParseIntPipe) id: number): Promise<void> { return this.tasksService.deleteTask(id); } @Patch('/:id') updateTask( @Param('id', ParseIntPipe) id: number, @Body('status',TaskStatusPipe) status: string ): Promise<Task> { return this.tasksService.updateTask(id, status); } } Moduleはリポジトリをimportしておきます。 tasks/tasks.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; // 追加 import { Task } from './task.entity'; // 追加 import { TasksController } from './tasks.controller'; import { TasksService } from './tasks.service'; @Module({ imports: [ TypeOrmModule.forFeature([Task]) // 追加 ], controllers: [TasksController], providers: [TasksService] }) export class TasksModule {} 確認 yarn run startで起動して確認します。 // get (登録なし) $ curl -X GET http://localhost:3000/tasks [] // create (1) $ curl -X POST http://localhost:3000/tasks -d 'title=Test' -d 'description=testDesc' {"title":"Test","description":"testDesc","status":"OPEN","id":1} // get (登録あり) $ curl -X GET http://localhost:3000/tasks [{"id":1,"title":"Test","description":"testDesc","status":"OPEN"}] // create (2) $ curl -X POST http://localhost:3000/tasks -d 'title=Nest' -d 'description=nestjs' {"title":"Nest","description":"nestjs","status":"OPEN","id":2} // get (id指定) $ curl -X GET http://localhost:3000/tasks/2 {"id":2,"title":"Nest","description":"nestjs","status":"OPEN"} // get (複数登録あり) $ curl -X GET http://localhost:3000/tasks [{"id":1,"title":"Test","description":"testDesc","status":"OPEN"},{"id":2,"title":"Nest","description":"nestjs","status":"OPEN"}] // update $ curl -X PATCH http://localhost:3000/tasks/2 -d 'status=DONE' {"id":2,"title":"Nest","description":"nestjs","status":"DONE"} // get (update確認) $ curl -X GET http://localhost:3000/tasks/2 {"id":2,"title":"Nest","description":"nestjs","status":"DONE"} // delete $ curl -X DELETE http://localhost:3000/tasks/2 // get (delete確認) $ curl -X GET http://localhost:3000/tasks [{"id":1,"title":"Test","description":"testDesc","status":"OPEN"}] // 不正な値の確認 $ curl -X POST http://localhost:3000/tasks -d 'title=Nest' -d 'description=' {"statusCode":400,"message":["description should not be empty"],"error":"Bad Request"} $ curl -X PATCH http://localhost:3000/tasks/2 -d 'status=aaa' {"statusCode":400,"message":"Bad Request"} まとめ NestJSを使って必要最低限なREST方式で実装してみました。 ここに紹介しているだけじゃなくNestJSには、もっと便利な機能がありますし拡張性が高いです。 (書いている途中で記事じゃなく本の方が見やすかったと後悔・・・) 唯一日本語ドキュメントが少ないという意見を良く見かけますが、今では日本語の記事も多くなってきて調べやすい環境になっているのかなと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NestJS+PostgreSQL(+pgAdmin4)の開発環境をDockerで構築する

はじめに NestJS + PostgreSQL(+ pgAdmin4)の開発環境を、dockerで構築する手順を紹介します。 バージョン情報 Docker : 19.03.13 Docker Compose : 1.27.4 Node.js : 14 PostgreSQL : 11.2 pgAdmin4 : 4.2 ディレクトリ構成 以下のような構成で作成します。 $ tree -L 2 . ├── api │   └── Dockerfile ├── app // コンテナ共有ディレクトリ │   └── [ project directory ] ├── db │   ├── pgadmin4 // DBサーバ接続永続化用ディレクトリ │   └── postgres // DBサーバデータ永続化用ディレクトリ └── docker-compose.yml Dockerfileの作成 公開されているNode.jsのdockerイメージを使い、PostgreSQLのライブラリを導入します。 ついでにちょっとしたファイル編集用にvimをインストールしておきます。 (主要なファイルは共有フォルダに置くので無くてもよい) FROM node:14 # share directory ENV ROOT="/app" # add path env ENV PATH $PATH:/usr/local/bin # set home directory RUN mkdir ${ROOT} WORKDIR ${ROOT} RUN apt-get update && apt-get upgrade -y # install lib (opt : vim) RUN apt-get install -y build-essential libpq-dev postgresql-client vim # install NestJS RUN npm install -g @nestjs/cli docker-compose.ymlの作成 NestJSアプリケーションを構成するコンテナ情報を記載します。 データベース操作用にpgAdmin4を入れてますが、端末に既に入ってたり、使用しないのであれば要らないです。 version: "3.7" services: api: build: api container_name: nest_api tty: true ports: - "3000:3000" volumes: - ./app:/app:delegated # share directory links: - db restart: always db: image: postgres:11.2 container_name: nest_db ports: - "5432:5432" volumes: - ./db/postgres/init.d:/docker-entrypoint-initdb.d - ./db/postgres/pgdata:/var/lib/postgresql/data environment: POSTGRES_USER: root # DB USER POSTGRES_PASSWORD: root # DB Password POSTGRES_INITDB_ARGS: "--encoding=UTF-8" hostname: postgres user: root restart: always pgadmin4: image: dpage/pgadmin4:4.2 container_name: pgadmin4 ports: - "8000:80" volumes: - ./db/pgadmin4:/var/lib/pgadmin environment: PGADMIN_DEFAULT_EMAIL: root # pgAdmin Address PGADMIN_DEFAULT_PASSWORD: root # pgAdmin Password hostname: pgadmin4 links: - db restart: always postgreSQL(pgAdmin4)に設定しているアドレス、パスワードはrootにしてますけど、そこは各自お任せします。 コンテナを作成&起動する 早速コンテナを作成、および起動します。 docker-compose build docker-compose up -d 起動後は、一応エラーがないか調べましょう。 (立ち上がらなかったら、原因調査に時間がかなり取られます) docker ps -a // 立ち上がってなかった場合、ログを見て原因調査 docker-compose logs コンテナにログインする 起動後はコンテナにログインし、プロジェクト作成の準備をします。 docker-compose exec api bash // 以下はログインした後にやってます。作業がやりやすいようにしてるだけなので必須ではないです。 echo 'export LS_OPTIONS='\''--color=auto'\' >> ~/.bashrc echo 'alias ll='\''ls $LS_OPTIONS -l'\' >> ~/.bashrc source ~/.bashrc PostgreSQLに接続できるか確認 一応、ちゃんと設定できているか確認。 psql -h db -U root -d postgres // rootを入力 Password for user root: psql (9.6.19, server 11.2 (Debian 11.2-1.pgdg90+1)) WARNING: psql major version 9.6, server major version 11. Some psql features might not work. Type "help" for help. // postgresのテーブルにログインできたら成功 postgres=# ん?なんか警告出てる。 クライアントとサーバ間のバージョン差異での警告みたい。 警告が出るだけで、特に問題ないからヨシ! ※ ヨシじゃねーだろ!って人は以下のコマンドでアップグレードしてください。 sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ stretch-pgdg main' > /etc/apt/sources.list.d/pgdg.list" wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - apt-get update apt-cache search postgresql | grep ^postgresql // postgresqlのバージョンが増えてるはずなので、対象のパッケージをインストールします。 // サーバ側を11で入れてるのでクライアントも11をインストールします。 apt-get install -y postgresql-client-11 NestJS新規プロジェクトを作成する コンテナ内でコマンドを発行します。 nest new [ New Project Name] // npm か yarn どっちを使用するか聞かれるので好みの方を選択する。 NestJS起動 作成したプロジェクトのディレクトリに移動して、NestJSを起動します。 cd [ Project directory ] // npm npm run start // yarn yarn run start 起動した後は、実際にブラウザで確認します。 localhost:3000にアクセスします。Hello Worldが表示されていたらOK おまけ: pgAdmin4の確認 pgAdmin4も接続確認してみます。 localhost:8000でアクセスできます。 アドレスとパスワードは、docker-compose.ymlに書いたrootで入ります。 ログインすると下記のような画面になります。 サーバを登録するための設定を行います。 Serversを選択した状態で右クリック→サーバの設定を行います。 サーバ名は自分が分かりやすい名前で。 Connectionタブでホスト名、ユーザ名、パスワードを入力して保存。 無事に接続できました。 最後に dockerコンテナでNestJSの開発環境を構築しました。 NestJSはAngularに似てるらしいです。 (触ったことがないので私は分かりません。ControllerとServiceはSpringに似てるなぁと思いました) ここからHTMLを返せるようにするもよし、TypeORMを入れるもよし。 どんどん使っていきましょ〜! 参考 NestJS公式 pgAdmin公式 水無瀬のプログラミング日記 - NestJS事始め
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

電力密度の計算方法

携帯電話の基地局から発射される電力密度の計算方法です。 等方(アイソロロピック)アンテナとしての計算です。 これは、1点から球状に電波が広がっていくとしたモデルです。 S: 電力密度 W/m^2 P: 電力 W (ワット) r: 距離 m S = P / (4 * pi * r^2) 計算例 電力 640W , 距離 5 m の場合 Node.js の例 $ node Welcome to Node.js v15.13.0. Type ".help" for more information. > 640 / (4 * Math.PI * 5**2) 2.0371832715762603 > TypeScript の例 $ npx ts-node > 640 / (4 * Math.PI * 5**2) 2.0371832715762603 Deno の例 $ deno Deno 1.0.0 exit using ctrl+d or close() > 640 / (4 * Math.PI * 5**2) 2.0371832715762603 python3 の例 $ python3 Python 3.9.2 (default, Feb 20 2021, 18:40:11) [GCC 10.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import math >>> 640 / (4 * math.pi * 5**2) 2.0371832715762603 >>> Go の例 $ gore gore version 0.5.2 :help for help gore> :import math gore> 640.0 / (4.0 * math.Pi * math.Pow(5.0,2.0)) 2.037183 2.04 W/m^2 は、0.204 mW/cm^2 になります。 参考、  日本の規制値は、0.1 mW/cm^2  ICNIRP の規制値は、0.09 mW/cm^2 指向性のアンテナの場合は、強い方向への補正と、弱い方向への補正が必要です。 コンクリートの壁などがあれば、弱い方向への補正が必要です。 コンクリートによる減衰は、材質、厚さにより異なります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む