- 投稿日:2020-11-28T23:25:49+09:00
Chatwork に Node.js + TypeScript でメッセージを通知する
スクリプト
ちょっとしたツールを作成していて Chatwork 通知が必要になりましたため、作成しました。
import { escape } from 'querystring'; import fetch from 'isomorphic-unfetch' export async function notify( api_token: string, room_id: string, message: string, self_unread?: 0 | 1 ): Promise<Response> { return await fetch(`https://api.chatwork.com/v2/rooms/${room_id}/messages`, { method: 'POST', headers: { 'X-ChatWorkToken': api_token, 'Content-Type': 'application/x-www-form-urlencoded', }, body: `body=${escape(message)}&self_unread=${ typeof self_unread === 'undefined' ? 1 : self_unread }`, }); }下記のライブラリのインストールが必要です。
# yarn の場合 $ yarn add querystring isomorphic-unfetch # npm の場合 $ npm install querystring isomorphic-unfetch
querystring.escape
で投稿するメッセージURLパーセントエンコードしています。
これがないと投稿内容にURLで使用できない文字が混ざった際に投稿が失敗します。また、
isomorphic-unfetch
はブラウザ(window.fetch
)、サーバー(node-fetch
)両方で動くfetch API
を提供してくれるため使用しています。使い方
async function main() { await notify( process.env.CHATWORK_API_TOKEN, process.env.CHATWORK_ROOM_ID, "テストメッセージです。" ); } main();Chatwork API
詳しい仕様は公式ドキュメントをご確認ください。
- 投稿日:2020-11-28T23:04:40+09:00
AmazonLinux node.js/typescriptのインストール手順
typescriptを始めたくてAmazonLinuxにnode.jsとtypescriptをインストールしてみた。
まずはcurlでリポジトリを追加してyumでnode.jsをインストールする。curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash - sudo yum install -y nodejsこれでLTSの14.x版がインストールされる。
次にnpmでtypescriptをインストールする。sudo npm install -g typescriptこれでtscが使えるようになり、typescriptのコンパイルができるようになった。
- 投稿日:2020-11-28T22:04:59+09:00
ハンズオン Node.jsの7章データストレージ(sqlite3)をTypescriptで試したメモ
概要
前回の続き。
ハンズオン Node.jsの7章データストレージをtypescriptで試す。今回はsqlite。環境
package.json{ "name": "node-app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node ./bin/www", "file-system": "node ./bin/www", "sqlite": "node ./bin/www", "tsc": "tsc", "watch": "tsc --watch" }, "keywords": [], "author": "", "license": "MIT", "engines": { "node": "14.x" }, "dependencies": { "express": "^4.17.1", "sqlite3": "^5.0.0", "uuid": "^8.3.1" }, "devDependencies": { "@types/express": "^4.17.9", "@types/sqlite3": "^3.1.6", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^4.8.2", "@typescript-eslint/parser": "^4.8.2", "eslint": "^7.14.0", "eslint-config-prettier": "^6.15.0", "eslint-plugin-prettier": "^3.1.4", "isomorphic-fetch": "^3.0.0", "prettier": "^2.2.0", "typescript": "^4.1.2" } }ソース
promisify
したときの型をtype PromiseDbGet = <T>(arg: string, arg2?: any) => Promise<T>
としているが、もうちょっとよい方法ないだろうかsrc/fqlite/index.tsimport { promisify } from 'util' import { join } from 'path' import type { ID, Todo, DataStorage } from '../types' import type { RunResult, sqlite3 as Sqlite3 } from 'sqlite3' interface TodoSQLite { id: ID title: string completed: 0 | 1 } type SQLiteArgs = [sql: string, ...params: any[]] type PromiseDbGet = <T>(arg: string, arg2?: any) => Promise<T> type PromiseDbAll = <T>(arg: string, arg2?: any) => Promise<T> const sqlite3: Sqlite3 = process.env.NODE_ENV === 'production' ? require('sqlite3') : require('sqlite3').verbose() const db = new sqlite3.Database(join(__dirname, 'sqlite')) const dbGet: PromiseDbGet = promisify(db.get.bind(db)) const dbRun = function (...args: SQLiteArgs) { return new Promise<RunResult>((resolve, reject) => db.run.apply(db, [ ...args, function (this: RunResult, err: any) { err ? reject(err) : resolve(this) }, ]), ) } const dbAll: PromiseDbAll = promisify(db.all.bind(db)) dbRun(`CREATE TABLE IF NOT EXISTS todo ( id TEXT PRIMARY KEY, title TEXT NOT NULL, completed BOOLEAN NOT NULL )`).catch((err) => { console.log(err) process.exit(1) }) function rowToTodo(row: TodoSQLite): Todo { return { ...row, completed: !!row.completed } } const exportsObj: DataStorage<Todo> = { fetchAll: () => dbAll<TodoSQLite[]>('SELECT * FROM todo').then((rows) => rows.map(rowToTodo), ), fetchByCompleted: (completed) => dbAll<TodoSQLite[]>( 'SELECT * FROM todo WHERE completed = ?', completed, ).then((rows: TodoSQLite[]) => rows.map(rowToTodo)), create: async (todo) => { await dbRun( 'INSERT INTO todo VALUES (?,?,?)', todo.id, todo.title, todo.completed, ) }, update: (id, update) => { const setColumns = [] const values = [] for (const column of ['title', 'completed'] as const) { if (column in update) { setColumns.push(` ${column} = ? `) values.push(update[column]) } } values.push(id) return dbRun( `UPDATE todo SET ${setColumns.join()} WHERE id = ?`, values, ).then(({ changes }) => changes === 1 ? dbGet<TodoSQLite>('SELECT * FROM todo WHERE id = ?', id).then( rowToTodo, ) : null, ) }, remove: (id) => dbRun('DELETE FROM todo WHERE id = ?', id).then(({ changes }) => changes === 1 ? id : null, ), } export default exportsObj参考
- 投稿日:2020-11-28T21:51:10+09:00
フロントエンドやるなら入れておくべきESlintってなに?
プログラミング勉強日記
2020年11月28日
昨日の記事でPrettierについて扱ったが、Prettierと合わせて使用することのできるESlintについて紹介する。ESlintとは
ESlint(読み方:「イーエスリント」)は、JavaScriptやTypeScriptなどの静的解析ツールである。ESlintを導入することで、単純な構文エラーやプロジェクト固有のコーディング規約を定義することができる。厳密なルールを定義することで、複数人で開発する場合でもシステム全体のコードの一貫性を維持することができる。
ESlintの特徴
- 自由に多くのルールを設定できる
- 独自ルールを作成するAPI
- 固有のライブラリー、フレームワーク、および実践のルールを持つ多数のプラグイン
- ES6、ES7、JSXの内蔵サポート
- 迅速に開始できるように、推奨ルールだけでなくサードパーティの設定利用が可能
- Sublime、Vim、JetBrainsの製品およびVisual Studio Codeなどの、複数のエディタやIDEとの統合が可能
(参考文献:JSプログラマーのイラッとする「クセ」はESLintを導入して対処しよう)
ESlintの導入方法
1. ESlintを使ってTypeScriptを解析するためのライブラリをインストールする
nodeのルートディレクトリに移動して、eslint, @typescript-eslint/parser, @typescript-eslint/eslint-plugin, eslint-plugin-reactの4つをインストールする。
コマンドプロンプトnpm install --save eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react2. ファイルを作成して設定する
eslintrc.jsonファイルを作成して、以下のように設定する。
.eslintrc.json{ "parser": "@typescript-eslint/parser", "extends": [ "plugin:react/recommended", "plugin:@typescript-eslint/recommended" ], "parserOptions": { "ecmaFeatures": { "jsx": true // Allows for the parsing of JSX } }, "rules": { "react/prop-types": "off", "@typescript-eslint/no-empty-interface": 0 }, "settings": { "react": { "version": "detect" } } }3. package.jsonにscriptを追加する
package.jsonにESLintが実行できるようにscriptsタグに以下のコマンドを追加する。今回は拡張子が
.ts
と.tsx
のみを対象に解析する。package.json"lint": "eslint . --ext .ts,.tsx"4. ESlintの実行
ターミナルnpm run lintPrettierとESlintが連携してフォーマットを適用させる場合
Prettierはリントツールと組み合わせて利用することができるので、すでにESlintを使用してるプロジェクトでも使用することができる。
PrettierとESlintと組み合わせて使用するためには、prettier-eslintとprettier-eslint-cliが必要になる。※Prettierの導入方法はこちらの記事で扱っている。
1. インストールする
Google JavaScript Style Guideに従ってeslint-config-googleをインストールする。
コマンドプロンプトnpm install -D prettier-eslint prettier-eslint-cli eslint-config-google2. ESlintの設定をする
プロジェクトフォルダのルートに、
.eslintrc.json
というファイルを作成して以下の内容を記述する。(Google JavaScript Style Guideに準拠したECMAScript 2018の仕様でリントチェックを行うように定義)..eslintrc.json{ "extends": ["google"], "parserOptions": { "ecmaVersion": 2018 } }次に、pakage.jsonに定義したscriptをprettier-eslintを使用したコマンドに変更する。
package.json{ "scripts": { "format": "prettier-eslint --write 'src/**/*.js'" }, "devDependencies": { "eslint-config-google": "^0.13.0", "prettier-eslint": "^8.8.2", "prettier-eslint-cli": "^4.7.1" } }3. 実行する
コマンドプロンプトから以下のコマンドを実行して、Prettierで直されたコードがESlintに渡されてESlintの整形も適応される。
コマンドプロンプトnpm run format参考文献
Next.jsを勉強してみる その⑤ 〜ESLintを導入する編〜
Prettierの導入方法
フロントエンド開発で必須のコード整形ツール
- 投稿日:2020-11-28T20:25:09+09:00
Twitterのリスト内ツイートを取得する際の`slug`の確認方法
TwitterのリストをAPIで使用する際、例えば
ninomiyt
アカウントのsample
リストを取得する際、以前は素直に以下のようなコードを書けば取得できました。node.jsのtwitterライブラリで書いていますが、他の言語でも概ね似たコードになると思います。
const response = await client.get("lists/statuses", { "owner_screen_name": "ninomiyt", "slug": "sample", "count": 100, });しかし、現在は新規作成したリストは、slugが作成した名前そのものではなく、
名前-数値
という値がセットされるようです。以下のようなコードで、lists/list
を使って取得して確かめてください。const result = await client.get("lists/list", { "screen_name": "ninomiyt" // あなたのアカウント名に書き換えてね! }); console.log(result);
- 投稿日:2020-11-28T17:12:04+09:00
SIerエンジニアからWeb系フロントエンドエンジニアに転身するために今やっていること
こんにちは!SIerでJavaプログラマをしているゆうきデザイン(@yuki_design_gr)と言います。
Qiita初投稿として、自己紹介も兼ねて
"SIerエンジニアからWeb系フロントエンドエンジニアに転身するために今やっていること"
というテーマで書いてみようと思います。同じような境遇にいる人の道しるべの1つになりますように!
目次
1. 自己紹介
2. なぜWeb系を目指すのか
3. SIerエンジニアからWeb系フロントエンドエンジニアに転身するために今やっていること1. 自己紹介
東京在住の20代半ば。
学歴
東京外大韓国語専攻卒業
職歴
新卒で大手SIerに入社し、アカウント営業を担当(10ヶ月)
→SE(現職。Java・.NET・Oracleのコーディング実務1年半)
→Web系企業への転職準備中モットー
技術とデザインのことをポジティブに共有すること
目標
・世の中をポジティブにするWebサービスを作ること
・ビジネスを始めたい・サービスを作りたい友だちをIT・デザイン面でサポートすること趣味など
韓国語と英語は日常会話レベル
持久系のスポーツが好き(陸上・水泳。社会人になってからもたまにやってる)
実写の動画編集
映画・音楽・コーヒー
ミスチルが生まれた時から好きで、人生ピンチの時に助けてくれる存在(←いま)さあ、本題に入ります!
2. なぜWeb系を目指すのか
①新しいものを追いかけるのが好きだから
音楽や映画などのエンタメや好きで、
SI業界よりもトレンドの移り変わりが激しいWeb業界が楽しそうに見えるため。②Webサービスを作りたいという目標があるから
自己紹介でも書いたように
世の中をポジティブにするWebサービスを作る
という目標があり、
SI業界に身を置くよりも目標実現への近道だと思っています。③システムの裏側の処理よりも見た目に魅かれるから
Javaエンジニアをしていてプログラミングは基本的に全般楽しいですが、
JSPやCSS等のシステムの見た目の開発が楽しく、
また他のメンバーが気にかけないレイアウトのズレなどに何度も気づくことができました。そのため、まずはWebデザイナーやUI・UXデザイナーに興味を持ち、
デザイナーのための勉強会などに参加してきました。しかし、自分のプログラマとしての経験を活かす×システムの見た目に寄与できる
というフロントエンドの技術が一番しっくりくるなあと今は思っています。3. SIerエンジニアからWeb系フロントエンドエンジニアに転身するために今やっていること
①フロントエンド技術に触れること
結局はどの言語がベスト!とかはなさそうなので
今は色々触ってみてます。フロント: react, vue, rails
バックエンドやインフラ等: node, ruby, docker, laravel
その他: TypeScript, Sass, Bootstrap色々触れる今の時期が一番楽しいですね。
何かを極めた方が勉強になる気もしますが。個人的にはnode + react(またはvue・angular) + TypeScriptがアツい気がします!
全部jsで書けるなんて!②フロントエンド技術を用いたWebアプリを作ってみること
上記のそれぞれの言語を使って
簡単なSNSやTodoリストをチュートリアルを見ながら作成中です。
ネット上に公開するところまでやりたいです。③SNSやGitHub、Qiita等でのアウトプット
個人的に苦手であまりできていないアウトプット。
でも見てる人との交流が生まれたり、自分の特性や技術力を客観視できる機会と思って、
定期的に取り組んでいきたいです。
この投稿の内容は以上です。
ここまで読んでいただきありがとうございます。
これからも有益な情報をポジティブに発信していきたいです。ぜひ、Twitter(@yuki_design_gr)のフォローもよろしくお願いします。
- 投稿日:2020-11-28T16:42:50+09:00
expressでOpenAPI仕様のAPIを実装するときのTips
要点
- express-openapiを使おう (openapi-generatorではなく)
- security handlerの実装には、シンプルにOpenAPIのinitializeメソッドに引数securityHandlersを渡すのが良い。(openapi-security-handlerは、必要ない)
express-openapiを使おう (openapi-generatorではなく)
OpenAPI仕様のYAMLファイルを Swagger Editor (https://editor.swagger.io/) などを用いて作った後、openapi-generator (https://github.com/OpenAPITools/openapi-generator) を使ってスケルトンを作れそう...と思うのですが、openapi-generatorの出力するNode.js向けのスケルトンは、あまり良い感じではないです。
むしろexpress-openapi (https://www.npmjs.com/package/express-openapi) の方が、使う機能だけ使って書くように考えられているので、やりたいことに集中できるように思います。
security handlerの実装には、シンプルにOpenAPIのinitializeメソッドに引数securityHandlersを渡すのが良い。(openapi-security-handlerは、必要ない)
APIサーバを実装するとき、ほとんどの場合、セキュリティのことも考えることになると思います。
このとき、express-openapiのHighlightsを見ると、こういうことが記述されています。
Leverages security definitions for security management.
* See openapi-security-handleropenapi-security-handlerを使う必要があるのかな...と感じますが、必要ありません。
express-openapiでセキィリティハンドラを実装するときは、initializeメソッドの引数secuurityHandlersを渡すのが正解です。
initialize({ apiDoc: apiDoc, app: app, securityHandlers: { keyScheme: function(req, scopes) { return Promise.resolve(true); } } });reqはexpressでおなじみのもので、scopesには、以下のようにAPIの定義のsecurityでスキーマ別に定義するスコープ配列が渡ってきます。
security: - keyScheme: [admin]セキュリティハンドラの戻り値は、即値でbooleanを返すか、booleanを返すPromiseとします。
trueが認証OKで、falseがNGです。
- 投稿日:2020-11-28T15:29:25+09:00
nodeJSとGoogleSpreadSheet(スプレッドシート)を連携する方法
nodeJSとスプレッドシートを連携して、スプレッドシート上の値を取得するところまでを解説します。
順序
①. auth情報を取得する
②. スプレッドシート側で権限を確認する
③. nodeJSのコードを書いて実行するの3本立てで説明しました。
①. auth情報を取得する
Google Cloud Platform(Google API)でGoogleSpreadSheetのAPIを有効化させます。すでに"サービスアカウント"の認証情報のjsonを持っている人は不要です
必須の入力箇所のみ適当に入れてあとは空白(もしくは任意)で進めていきます。
プロジェクトを立てたら「APIとサービス」へいって下記の流れでGoogle Spread Sheet APIを有効化させます。
画面の左端の方の「認証情報」をクリックしてから「認証情報を作成」をクリックします。下記の流れで"サービスアカウント"を作成してキーの入ったjsonファイルをDLします。
必須項目より他は空白で大丈夫です(もしくは任意)
画面左端の「認証情報」のページを改めて開くと"サービスアカウント"の中にアカウントが追加されているのでクリックします。
ここでjsonファイルとして鍵をDLすればGoogle API側の準備は完了です。
②. スプレッドシート側で権限とスプレッドシートIDを確認する
ユーザーやグループと共有の中に自分が権限を与えたいメールアドレスが含まれているかどうかを確認し、なければ追加します。
ここで、①. で用意した秘密鍵の中身を確認してください。
{ "type": "service_account", "project_id": "test", "private_key_id": "hoge", "private_key": "hoge, "client_email": "ここにスプレッドシート側で権限が付与されているメールアドレスを入力する", "client_id": "hoge", ー以下略ー }client_emailの中のメールアドレスはスプレッドシート側で権限を付与されたメールアドレスになります。
次にスプレッドシートIDを確認します。
スプレッドシートのページのURLに含まれており、ランダムな英字と記号となっています。スプレッドシートの部分をコピーしておきます。
https://docs.google.com/spreadsheets/d/スプレッドシートID/edit=hoge③. nodeJSのコードを書いて実行する
では①. と ②.の過程で準備した情報を使って見ます。ライブラリを用意。
yarn add google-spreadsheet-as-promised or npm install --save google-spreadsheet-as-promisedAuth認証→スプレッドシートの1行目のAからDまでを取得するコードです。スプレッドシートに適当な文字を入力して、下記コードを実行してみてください。
spreadsheet.jsconst GoogleSpreadsheetAsPromised = require('google-spreadsheet-as-promised'); const CREDS = require('./GoogleCloudからDLしてきた鍵.json'); const SHEET_ID = 'あなたのスプレッドシートID'; const spreadSheet = async() => { console.log('GoogleSpreadSheetへアクセス開始します'); const sheet = new GoogleSpreadsheetAsPromised();; await sheet.load(SHEET_ID, CREDS); console.log('auth完了'); const worksheet = await sheet.getWorksheetByName('sheet1'); const cells = ( await worksheet.getCells('A1:D1') ).getAllValues(); // A1からD1までの値を取得する console.log(cells); return(sheet); } spreadSheet();const worksheet = await sheet.getWorksheetByName('sheet1');のところは任意のシート名にします。読み込めなかった場合はシート名も見直してみてください。
結果として配列の結果が取得できたと思います。
- 投稿日:2020-11-28T11:18:04+09:00
ハンズオン Node.jsの7章データストレージ(file-system)をTypescriptで試したメモ
概要
ハンズオン Node.jsの7章データストレージを試す。
型をつけて、typescriptで書いてみる。
今回はfile-systemの章。
環境はnodeのexpressをtsで作って無料でazureに公開したメモで作成したものを利用した環境
package.json{ "name": "node-app", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node ./bin/www", "file-system": "node ./bin/www", "tsc": "tsc", "watch": "tsc --watch" }, "keywords": [], "author": "", "license": "MIT", "engines": { "node": "14.x" }, "dependencies": { "express": "^4.17.1", "uuid": "^8.3.1" }, "devDependencies": { "@types/express": "^4.17.9", "@types/uuid": "^8.3.0", "@typescript-eslint/eslint-plugin": "^4.8.2", "@typescript-eslint/parser": "^4.8.2", "eslint": "^7.14.0", "eslint-config-prettier": "^6.15.0", "eslint-plugin-prettier": "^3.1.4", "isomorphic-fetch": "^3.0.0", "prettier": "^2.2.0", "typescript": "^4.1.2" } }ソース
メインのソース
- ステータスコードは数字でみても分かりにくいので定数にした
app.tsimport express from 'express' import { v4 as uuidv4 } from 'uuid' import { statusCode, paths } from './constants' import type { Todo, DataStorage, HttpError, MiddlewareHandler } from './types' // const dataStorage: DataStorage<Todo> = require(`./${process.env.npm_lifecycle_event}`) // .default const dataStorage: DataStorage<Todo> = require('./file-system').default const app = express() app.use(express.json()) // ToDo一覧の取得 app.get(paths.todos, (req, res, next) => { if (!req.query.completed) { return dataStorage.fetchAll().then((todos) => res.json(todos), next) } const completed = req.query.completed === 'true' dataStorage.fetchByCompleted(completed).then((todos) => res.json(todos), next) }) // ToDoの新規登録 app.post(paths.todos, (req, res, next) => { const { title } = req.body if (typeof title !== 'string' || !title) { const err: HttpError = new Error('title is required') err.statusCode = statusCode.BadRequest return next(err) } const todo = { id: uuidv4(), title, completed: false } dataStorage .create(todo) .then(() => res.status(statusCode.Created).json(todo), next) }) // Completedの設定、解除の共通処理 function completedHandler(completed: boolean): MiddlewareHandler { return (req, res, next) => dataStorage.update(req.params.id, { completed }).then((todo) => { if (todo) { return res.json(todo) } const err: HttpError = new Error('Todo not found') err.statusCode = statusCode.NotFound next(err) }, next) } // ToDoのCompoetedの設定、解除 app .route(`${paths.todos}/:id/completed`) .put(completedHandler(true)) .delete(completedHandler(false)) // Todoの削除 app.delete(`${paths.todos}/:id`, (req, res, next) => dataStorage.remove(req.params.id).then((id) => { if (id !== null) { return res.status(statusCode.NoContent).end() } const err: HttpError = new Error('Todo not found') err.statusCode = statusCode.NotFound next(err) }, next), ) export default appfile-system/index.tsimport { extname } from 'path' import { readdir, readFile, writeFile, unlink } from 'fs/promises' import type { Todo, DataStorage } from '../types' const exportsObj: DataStorage<Todo> = { fetchAll: async () => { const files = (await readdir(__dirname)).filter( (file) => extname(file) === '.json', ) return Promise.all( files.map((file) => readFile(`${__dirname}/${file}`, 'utf8').then(JSON.parse), ), ) }, fetchByCompleted: (completed) => exportsObj .fetchAll() .then((all) => all.filter((todo) => todo.completed === completed)), create: (todo) => writeFile(`${__dirname}/${todo.id}.json`, JSON.stringify(todo)), update: async (id, update) => { const filename = `${__dirname}/${id}.json` return readFile(filename, 'utf8').then((content) => { const todo = { ...JSON.parse(content), ...update } return writeFile(filename, JSON.stringify(todo)).then(() => todo) }) }, remove: (id) => unlink(`${__dirname}/${id}.json`).then( () => id, (err) => (err.code === 'ENOENT' ? null : Promise.reject(err)), ), } export default exportsObjconstants.tsimport type { ValueOf } from './types' export const statusCode = { Created: 201, NoContent: 204, BadRequest: 400, NotFound: 404, } as const export type StatusCode = ValueOf<typeof statusCode> export const paths = { todos: '/api/todos' }型定義
- 各ファイルに分かれた定義をまとめてexport
types/index.d.tsexport type * from './storage' export type * from './todo' export type * from './utils' export type * from './http'
- ハンズオンに書かれていたStorageの仕様を型にした
types/storage.d.tsimport type { ID } from './common' import type { OptionalKeys } from './utils' export interface DataStorage<T> { fetchAll: () => Promise<T[]> fetchByCompleted: (completed: boolean) => Promise<T[]> create: (todo: T) => Promise<void> update: (id: ID, update: OptionalKeys<T>) => Promise<T | null> remove: (id: ID) => Promise<ID | null> }
- 型を定義するための汎用的な型をutilsとしてまとめた
types/utils.d.tsexport type ValueOf<T> = T[keyof T] export type OptionalKeys<T> = { [K in keyof T]?: T[K] | null }
- IDはエイリアスを切っただけ
types/common.d.tsexport type ID = stringtypes/todo.d.tsimport type { ID } from './common' export interface Todo { id: ID title: string completed: boolean }
- ErrorにはstatusCodeプロパティがないので自前で定義
- expressの、引数を3つとるMiddlewareの型がなかったのでRequestParamHandlerを参考に定義
http.d.tsimport type { Request, Response, NextFunction } from 'express' import type { StatusCode } from '../constants' export interface HttpError extends Error { statusCode?: StatusCode } export type MiddlewareHandler = ( req: Request, res: Response, next: NextFunction, ) => voidテスト
- テストはVsCodeのREST Client拡張を使用した
tools/connectionTest/todos.azure.httpGET https://az-node-app.azurewebsites.net/api/todos HTTP/1.1 ### POST https://az-node-app.azurewebsites.net/api/todos HTTP/1.1 content-type: application/json {"title": "テスト"} ### # タイトルがないと400エラー POST https://az-node-app.azurewebsites.net/api/todos HTTP/1.1 content-type: application/json {} ### # 一つ目の要素をcompletedにする PUT https://az-node-app.azurewebsites.net/api/todos/29010728-d64e-4db2-b49e-d7c2daf09a9a/completed HTTP/1.1 ### # 一つ目の要素のcompletedを解除 DELETE https://az-node-app.azurewebsites.net/api/todos/29010728-d64e-4db2-b49e-d7c2daf09a9a/completed HTTP/1.1 ### # 一つ目の要素を削除 DELETE https://az-node-app.azurewebsites.net/api/todos/29010728-d64e-4db2-b49e-d7c2daf09a9a HTTP/1.1参考
- 投稿日:2020-11-28T10:05:32+09:00
【Nuxt.js】Vue CLIによりアプリケーション雛形を作るまで
言語化するために記事に起こしました。
汎用性の高いスターターテンプレートで雛形を作成するまでを簡潔に記します。事前準備
①Node.jsの導入
②Yarnの導入
③direnvの導入①、②共にNuxt.jsで開発する上で必須となるので導入する(ここではこれらの導入方法については省略します)。
③はターミナルのcurrentディレクトリで環境変数を自動で設定してくれるツール。環境変数の設定忘れを防止するため導入するとよい。
1
ターミナルnpm i -g @vue/cli @vue/cli-init上記コマンドで、Vueコマンドを追加する。「Vue -V」でバージョン確認。
ターミナル$ vue -V @vue/cli 4.5.92
1により、「vue init」コマンドでプロジェクト作成可能。
今回は初学者やカスタマイズして利用したい方におすすめのテンプレートである、「my-first-nuxt-app」を利用する。desktop$ vue init nuxt-community/starter-template my-first-nuxt-appインストール中のいくつかの質問は全てEnterでOK。
作成後、ターミナル$ cd my-first-nuxt-app #ディレクトリに移動 $ yarn #パッケージをインストール $ yarn dev # 開発モードでプロジェクトを起動OPEN http://localhost:3000
と表示後、上記URLにアクセスする。3
このような表示が出れば完了です!