35. A set of best practices for JavaScript projects
【所要時間】
7時間6分(2018年8月16,17日)
【概要】
プロジェクトのベストプラクティス
【要約・学んだこと】
1. Git
1.1 Some Git rules
- feature branchで作業を実行する。
メインブランチではなく専用のブランチで孤立して作業を行うことで、不安定で未完成のコードでmaster branchを汚さずに反復作業ができるから。 - developからbranch outする。
masterのコードが常に問題なしで構築されていることを確認するため。 - developかmasterに絶対にpushしない。pull requestを作る。
チームメンバーに機能が完成したことを知らせるため。また、簡単な査読や提案された機能について議論するフォーラムを与えるため。 - featureをプッシュし、pull リクエストをする前に、ローカルdevelop branchを更新して、interactive rebaseを行う。
rebaseは要求されたbranch(master か develop)でmergeする。merge commit(競合がないとして)を作成せずに、ローカルで行ったcommitを履歴の先頭に適用する。 - pull requestをする前に、rebase中に潜在的な衝突を解決する。
- mergeをしたら、localとremoteのfeature branchを削除する。
branch(master または develop)を1回だけmergeする。feature branchは開発途中だけ存在するようにする。 - pull requestをするまえに、確実にfeature branchを正しく構築し、全てのテストを終える。(code style checkを含む。
もしfeature-branchのテストがうまくいかないと、目的のbranchの構築も失敗する。さらに、読みやすさを助け、実際の変更で修正がフォーマットされる可能性をへらす。 - this
.gitignore
file を使うこと。
remote repositoryに送るべきではないシステムファイルのリストがすでにある。加えて、ほとんどのdependencyフォルダ、エディタ、フォルダやファイルの設定は除外されている。 - developとmaster branchを守る。
1.2 Git workflow
上記の理由から、Feature-branch-workflow with Interactive Rebasing and some elements of Gitflow (naming and having a develop branch)を使う。
- 新しいプロジェクトでは、プロジェクトのディレクトリのgit repositoryを初期化する。それ以降ではこのステップは無視する。
cd <project directory>
git init
- new feature/bug-fix branchにcheckoutし、変える。
git checkout -b <branchname>
git add
git commit -a
git commit -aは、エディターを起動し、ボディから主題を分ける。
- remoteと同期して見逃したチェンジを取得。
git checkout develop
git pull
競合を含むpull requestを作るのではなく、rebaseしながらマシンの競合に対処する機会を与える。
- feature branchとdevelopの最新のチェンジをinteractive rebaseで更新する。
git checkout <branchname>
git rebase -i --autosquash develop
autosquashを使うと、全てのcommitを1回のcommitにスカッシュできる。developブランチで単一の機能に対して多くのcommitを望む人はいない。
- 競合があったら、解決してからrebaseを続ける。 なければこれは飛ばす。
git add <file1> <file2> ...
git rebase --continue
- branchをpushする。rebaseが履歴を変えるので、remote branchに変更を-f を使って強制する必要がある。もし誰かがこのburanchで作業していたら、破壊が少ない — force-with-leaseを使う。
git push -f
rebaseをするとき、feature branchの履歴を変える。結果として、Gitは通常のgit pushを拒否する。その代わり、-f か、 — force flagを使う必要がある。
- pull requesetをする。
- pull requestがレビュアーに受け入れられmergeし、クローズする。
- local feature branchを消す。
git branch -d <branchname>
remote ではなくなった全てのブランチを消去する。
git fetch -p && for branch in `git branch -vv --no-color | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done
1.3 Writing good commit messages
コミットを作成し、それに固執するためのいいガイドラインを持つことが、Gitと他者との共同作業を可能にする。(source)
bodyと件名には2行の改行を入れて分ける。
Gitは1行目を要約だと区別する。
- 件名の行は50文字までにし、ボディを72文字で囲む。
commitは可能な限り細かくする。冗長な場所ではない。
- 件名の行は大文字にする。
- 件名の行はピリオドで終わらない。
- 件名の行では imperative mood を使う。
コミッターが何をしたかを書くのではなく、コミットがこのレポジトリで適用された後に、何が行われるかの指示として考えるのが良い。
- bodyでは何を、なぜ、どうやってを使って説明する。
2. Documentation
README.md
にはこのテンプレートを使う。template- レポジトリが2つ以上あるプロジェクトには、それぞれの
README.md
にそれぞれのリンクを載せる。 README.md
ファイルは更新があるたびに最新の状態にする。- コードにはコメントをし、それぞれのメジャーセクションで何を意図しているのかをはっきりさせる。
- コードや使っているアプローチでgithubかstackoverflowでディスカッションが開かれている場合は、コメントにそのリンクを含む。
- 悪いコードの言い訳にコメントを使わず、綺麗なコードを保つ
- コメントをしない言い訳にクリーンなコードを使わない。
- コードが変わるにつれて、コメントを関連づける。
3. Environments
- 必要ならばdevelopment, test, productionの環境を別に定義する。
データ、トークン、API、ポートなどは異なる環境を必要とする。予測できるデータを返し、自動と手動テストを簡単にするfake APIと呼ばれる孤立したdevelop modeを使いたいだろう。もしくは、Google Analyticsをproductionなどでのみ使うことを望むだろう。
- environment variableからdeployment specific configuration(デプロイメント固有の設定)をロードし、決してconstantとしてコードに加えない。このsample.参照。
理由
token, password, その他のvaluable informationがそこにある。configはコードベースをいつでも公開できるように、アプリ内部から正しく別れていなければならない。
方法
.env fileがvariableを格納し、それらを.gitignoreに追加し、除外する。その代わり、developerのためにガイドとして.env.exampleをcommitする。プロダクションには、標準の方法で自分のenvironment variableをセットする。 more
- environment variableをアプリを始める前に検証することが推奨される。他人がトラブルシューティングに時間を使わないようにするためだ。
3.1 Consistent dev environments:
- package.jsonのenginesにnode versionをセットする。他人にプロジェクトが動作するnode versionを教えるためだ。 read more…
- 加えて、 nvm を使い、プロジェクトルートの .nvmrc を作る。ドキュメントでそれについて言及することを忘れない。なぜなら、nvmを使う人がnvm use で適切なnode versionをスイッチできるようにするためだ。 read more...
- node と npm をチェックするpreinstall scriptをセットすると良い。新しいバージョンのnpmでインストールされた場合、いくつかのdependencyが失敗することがあるからだ。
- 可能であれば Docker imageを使う。ワークフロー全体で一貫した環境を提供できる。dependencyやconfigに頼る必要がなくなる。 read more…
- ローカルモジュールをグローバルインストールドモジュールの代わりに使う。同僚のシステム上でグローバル共有する代わりに、自分のツールを同僚と共有することができるからだ。
3.2 Consistent dependencies:
- チームメンバーが自分と正確に同じdendencyを使っていることを確かめる。なぜなら期待している通りにコードを動作させ、いかなる開発マシンでも同じにしたいからだ。Read more…
方法npm@5
以降のpackage-lock.json
を使う。
npm@5
を持っていなければ、代わりにYarnを使うことができる。README.md
で必ず記述すること。ロックファイルと、package.jsonはdependencyの更新後の同一バージョンを持たなければいけない。 read more...- Yarnもない場合。古いバージョンのnpmでは、新しいdependencyをインストールするときに-save — save-exactを使用し、公開前にnpm-shrinkwrap.jsonを作成する。 read more...
4. Dependencies
- 現在使えるパッケージを使い続ける。e.g.,
npm ls --depth=0
. read more... - 使用できないパッケージか、無関係かを確認する。
depcheck
. read more...
理由
コードに使用していないライブラリを含むことで、バンドルサイズを増やす。未使用のdependencyを探し、それらを取り除く。
- dependencyを使う前に、ダウンロード統計をチェックし、コミュニティーによって頻繁に使われているかどうかを確認する。
npm-stat
. read more...
理由
たくさん使われているということは、よりメンテナンスされているということを意味する。これが素早いバグの発見と修正につながる。
- dependencyを使う前に、たくさんの管理者によって、成熟したversion頻繁にがリリースされているかを確認。e.g.,
npm view async
. read more... - あまりよく知らないdependencyが必要なら、チームメンバーと事前に打ち合わせる。
- アプリがbreakなしで、dependencyの最新のバージョンで動作するかを確認。
npm outdated
. read more...
理由
dependency updateは時にbreakのチェンジを含む。常に更新がリリースされたのを確認する。万が一何かおかしくても、アップデートのリリース毎に確認すればトラブルシューティングが簡単になる。これらのツールを使うと便利。 npm-check-updates.
- パッケージセキュリティの脆弱性があるかどうか確認。 e.g., Snyk.
5. Testing
- 必要であればtest mode environmentを用意する。
理由
production modeでテストをすので十分であることもときどきあるが、例外もある。’production!’ modeのアナリティカル情報が欲しくない時や、テストデータで他人のダッシュボードを汚す時などだ。他にもAPIがproductionでレート制限を持つことがあり、一定の要求後にテストを呼び出しブロックすることだ。
- moduleName.spec.js などの *.test.js または *.spec.js 命名規則を使って、テストされたモジュールの隣にテストファイルを置く。なぜならユニットテストを探すために、フォルダの奥まで見たくないからだ。 read more…
- 混乱を避けるために別のテストフォルダに追加テストファイルを置く。
理由
テストファイルによっては、特定の実装ファイルに関連しない。他のディベロッパーに最も発見されやすいフォルダーに置かなければならない。__test__
folder. この: __test__
はスタンダードな名前だ。
- 副作用を避け、抽出し、ピュアなfunctionを書くために、テストができるコードを書く。なぜならビジネスロジックを別のユニットとしてテストしたい。ランダム性とコードの信頼性の非決定論的プロセスのインパクトを最小限に抑える必要があるからだ。 read more…
- ピュアfunctionは同じinputに同じoutputを常に返すfunctionだ。逆にアンピュアfunctionは、副作用があるか、外部の条件次第でvalueを作るfunctionだ。これは予測しにくい。 read more…
- 静的type チェッカーを使う。なぜならコードにあるレベルの信頼性をもたらすからだ。read more…
- developにpullを要求する前に、ローカルでテストをする。
理由
production-ready branchの構築に失敗を引き起こしたくない。feature-branchをリモートレポジトリにpushする前、そしてrebaseの後にテストを行う。
README.md
fileの該当するセクションにある指示を含めて、テストをドキュメント化する。他のディベロッパーや、専門家やQAのために残す便利なメモだ。
6. Structure and Naming
役割ではなく、製品機能、ページ、コンポーネントの周りにファイルを整理する。また、実装の横にテストファイルを置く。
悪い例
.
├── controllers
| ├── product.js
| └── user.js
├── models
| ├── product.js
| └── user.js
いい例
.
├── product
| ├── index.js
| ├── product.js
| └── product.test.js
├── user
| ├── index.js
| ├── user.js
| └── user.test.js
理由
長いリストファイルの代わりに、テストなどを含む1つの責任をカプセル化する小さいモジュールを作る。ナビゲートが簡単になり、一目で発見できる。
- 混乱を避けるためb、別のテストフォルダーにテストファイルを追加する。他のディベロッパーやチームの専門家の時間の節約のためだ。
./config
folder を使い、異なる環境に異なるconfig fileを作らない。
理由
config ファイルを別の目的(データベース、APIなど)に分解する時、configのような意味のわかりやすい名前のフォルダに置くことが重要だ。
./scripts
folderにスクリプトを置く.bashやnodeスクリプトも含む。 なぜなら2つ以上のスクリプト、プロダクションビルド、開発ビルド、データベースフィーダ、データベース同期などで終わる可能性が非常に高いからだ。./build
folderにbuilt output を置く。.gitignore
にbuild/
を追加する。
理由
名前はチームで一貫性を保つ。そこに入るものは、そこに作られる(バンドル、コンパイル、transpiled)か移動される可能性が高い。自分が作れるものはチームメイトも作れる可能性が高い。そのため、特別な理由なしでリモートレポジトリにコミットとする理由はない。
7. Code style
7.1 Some code style guidelines
- 新しいプロジェクトにはstage-2以降のJS syntaxを使う。古いプロジェクトは意図がなければそのままのsyntaxを使う。なぜならstage-2は最終的に仕様の一部になる可能性が高くなる。
- ビルドプロセスにコードスタイルのチェックを含める。なぜなら、buildを中断することは、コードにコードスタイルを適用する方法の1つで、クライアント側とサーバー側のコードの両方に対して実行する。read more…
- ESLint — Pluggable JavaScript linter を使い、コードスタイルを適用する。なぜなら単にeslintを好み、よりルールサポートもち、ルールをセットしたり、カスタムを加えるのうりょくがあるからだ。
- Airbnb JavaScript Style Guide のJSを使う。Read more. プロジェクトかチームに要求されたJS style guideを使う。
- FlowType を使うときは、 Flow type style check rules for ESLint を使う。なぜなら、フローには特定のコードスタイルにしたがってチェックする必要があるsyntaxはほとんどないからだ。
.eslintignore
をコードスタイルチェックのファイルかフォルダーを覗くために使う。なぜならスタイルチェックからファイルを除外する必要があるときは、eslint-disable コメントでコードを汚さないからだ。- eslint disable commentをpull requestする前に除外する。なぜならロジックによりフォーカスを当てるため、コードブロックを操作しながらスタイルチェックを無効にするのが普通だからだ。eslint-disableコメントを削除し、ルールに従う。
- タスクのサイズ次第で、
//TODO:
comments を使うか、チケットを開く。なぜなら、スモールタスク(functionのリファクタリングや、コメントの更新など)を自分や他人にリマインドできるからだ。ラージタスクでは、lintルールに強制される//TODO(#3456)を使い、ナンバーはオープンチケットになる。 - 常にコメントし、コードを変えるごとに関連性を保つ。コメント付きのコードのブロックは削除する。なぜならコードは可能な限り読みやすくするために、不要なものは全て取り除くべきだからだ。もしfunctionをリファクタしたいなら、ただ古いのにコメントするのではなく、取り除く。
- おかしなコメントや無関係なコメント、ログ、名前をつけない。なぜなら会社やクライアントに引き継がれるからだ。
- サーチできる意味のある区別できる名前をつけ、名前の省略を避ける。functionでは長い記述的な名前を使う。function nameは動詞か動詞句を使い、その意図を伝える。なぜならより自然にコードを読めるようになるからだ。
- ステップダウンルールにしたがってファイル内の機能を整理する。よりハイレベルなfunctionは、トップにおき、低いレベルの下にする。なぜならより自然にコードを読めるからだ。
7.2 Enforcing code style standards
- .editorconfig fileを使う。これはディベロッパーが定義をするのに役立ち、異なるエディターとプロジェクトのIDE間で、一貫性のあるコードスタイルを維持する。
理由
EditorConfig projectはコーディングスタイルを定義するファイルフォーマットと、エディタがファイルフォーマットを読むことを可能にし、定義されたスタイルに従うテキストエディタプラグインのコレクションで構成されている。EditorConfigファイルは、簡単に読め、バージョンコントロールシステムと相性良く働く。
- エディターはコードスタイルのエラーを知らせる機能を持つ。 eslint-plugin-prettier and eslint-config-prettier read more…
- Git hookを使うことを考える。なぜならGit hooksは生産性を大幅にあげるからだ。変更、コミット、stageへのプッシュや、buildの破損の恐れがない製品環境などだ。read more…
- 事前にコミットしたhookでPrettierを使う。
理由
prettier自身がパワフルだが、フォーマットコードをするたびに、npm taskを単独で実行するのは生産的ではないからだ。lint-stage(とhusky)が出る場所だ。configuringの lint-staged
について詳しくは、here and on configuring husky
here.
8. Logging
- 製品では、クライアント側のconsole logを避ける。なぜなら、build processがそれらを除けるけども、コードスタイルチェッカーが残りのconsole logの渓谷をするようにするためだ。
- 読みやすいプロダクションロギングを作成する。プロダクションモード(winston や node-bunyan など)で使われるロギングライブラリを使うのが理想。
理由
カラー化、タイムスタンプ、コンソールに加えてのファイルへのログ、または変わるファイルへのログによっても、トラブルシューティングが不快にならないようになるからだ。 read more…
9. API
9.1 API design
分別を持って構築されたRESTful interfaceの開発を強制するため、メンバーとクライアントは簡単に、一貫して消費することができる。
一貫生や単純さにかけたものは、統合がとても増え、メンテナンスにコストがかかる。そのため、API designはこのドキュメントに含まれる。
- 主にリソース思考設計に従う。リソース、コレクション、URLsの3つの要素がある。
- リスースはデータを持ち、ネストされ、それに対して動作するメソッドがある。
- リソースのグループはコレクションと呼ばれる。
- URLはリソースやコレクションのオンライン上の場所を示す。
理由
これはとてもよく知られたディベロッパーのためのデザインだ。(メインAPIコンシューマー) 読みやすさや使いやすさとは別に、APIが何かを知らなくても、汎用ライブラリとコネクタを書くことができる。
- URLにはkebab-caseを使う。
- クエリ文字列またはリソースフィールドのparameterにはcamelCaseを使う。
- URLのリソース名には複数のkebab-caseを使う。
- コレクションを指すURLにはいつも複数系の名刺を使う。 /users. なぜなら基本的に読みやすく、URLの一貫性を保つからだ。read more…
- ソースコードは複数のvariableとList suffix の property に変換する。なぜなら、複数系はURLではよいが、ソースコードでは誤りがちだからだ。
- 常にコレクションで始まり、identifierで終わる単一のコンセプトを使う。
/students/245743
/airports/kjfk
- 下記のようなURLを避ける
GET /blogs/:blogId/posts/:postId/summary
なぜならリソースを指さず、propertyを代わりに指すからだ。parameterをpropertyとして渡すと、レスポンスをトリミングすることができるからだ。
- リソースURLに動詞を入れない。なぜならそれぞれのリソースoperationに動詞を使うと、すぐに巨大なURLリストができ、一貫したパターンがなくなり、ディベロッパーが学習するのが困難になるからだ。
- ノンリソースにはverbを使い、APIはいかなるリソースも返さない。代わりに、operationを実行し、結果を返す。これらはCRUD(create, retrieve, update, delete) operationではない。
/translate?text=Hallo
理由
CRUDではリソースまたはコレクションURLでHTTPメソッドを使うからだ。動詞は実際はControllersだ。read more…
- リクエストのボディやレスポンスタイプはJSONで、 一貫性を維持するために、JSON property名のcamelCaseに従う。なぜならこれはJS projectのガイドラインだからだ。JSONを生産、解析するためのJSONは、 JSと見なされる。
- リソースはobjectのinstanceやデータベースレコードに似た単一のコンセプトであるが、リソースネームやcolumn_name resource property のtable_nameを使うべきではない。なぜなら意図がデータベース概要詳細ではなく、リソースを公開することだからだ。
- リソースに名前をつけるときは、URLには名詞だけを使い、機能の説明をしようとしない。なぜなら、リソーズURLで名詞だけを使い、/addNewUser や /updateUserといったエンドポイントは避ける。また、parameterとしてリソースoperationを送るのを避ける。
- HTTPメソッドを使い、CRUD functionalityを説明する。
方法
- GET: リソースの表現を検索
- POST: 新しいリソースやサブリソースを作成
- PUT: 存在するリソースを更新
- PATCH: 存在するリソースを更新。供給されたフィールドのみを更新し、他のはそのままにする。
- DLETE: 存在するリソースを消す。
- nested リソースは、URL内のリレーションを使用する。例えばidを使用して従業員を会社に関連づける。なぜならこれはリソースを探索可能にする自然な方法だからだ。
方法
- -
GET /schools/2/students
, school2から全てのstudentのリストを取得する。 GET /schools/2/students/31
, school2に所属する。student31の詳細を取得する。DELETE /schools/2/students/31
, school2に所属するstudent31を消すPUT /schools/2/students/31
, student31の情報を更新する。 リソースURLでのみPUTを使い、コレクションではつかはない。POST /schools
,新しいschoolを作り、新しいschoolの詳細を返す。コレクションURLでPOSTを使う。
-v prefix(v1, v2)をもつバージョンには単純な序数を使う。URLの一番左に移動し、一番範囲が大きくなるようにする。
http://api.domain.com/v1/schools/3/students
理由
APIが他のサードパーティのとき、APIをいくつかの変更を加えてアップグレードすると、APIを使用している既存の製品やサービスが中断される可能性があるから。 read more…
- レスポンスメッセージは自己記述的でなければならない。いいエラーメッセージレスポンスはこのようなものだ。
{
“code”: 1234,
“message” : “Something bad happened”,
“description” : “More details”
}
- 検証エラーの場合は
{
"code" : 2314,
"message" : "Validation Failed",
"errors" : [
{
"code" : 1233,
"field" : "email",
"message" : "Invalid email"
},
{
"code" : 1234,
"field" : "password",
"message" : "No password provided"
}
]
}
理由
ディベロッパーは、APIを使って構築したアプリケーションがユーザーの手元に置いてからトラブルシューティングや問題を解決する重大な時に、よく設計されたエラーに依存するから。
Note:
セキュリティ例外メッセージは可能な限り一般的なものとする。例えば、’incorrect password’の代わりに、invalid username or password’とリプライすることで、ユーザー名はあっているが、パスワードのみ違うことを無意識にユーザーに知らせなくてもよい。
- これらのステータスコードを使い、全てが機能しているかどうか記述するためにするために、レスポンスを送ることができる。
- Which ones:
200 OK
はGET, PUT, POSTのいずれかが成功したことを表すレスポンス201 Created
新しいインスタンスが作られたときに作られる。POST methodを使い、201 status codeを返し、新しいインスタンスを作る。204 No Content
レスポンスの成功を表すが、レスポンスの中に送られたコンテンツがない。 DELETE operationが成功した時に使う。304 Not Modified
レスポンスは、受信者がすでにキャッシュされた表現を持っている場合、情報の転送を最小限に抑える。400 Bad Request
クライエントが何を訪ねているのかサーバーが理解できなかったため、リクエストが進まなかった時に表示する。401 Unauthorized
リクエストが有効な証明を欠いていて、証明を再リクエストするべきときに表示する。403 Forbidden
サーバーがリクエストを理解したが、それが承認されなかった時に表示する。404 Not Found
要求されたリソースが見つからなかった時に表示される。500 Internal Server Error
リクエストは有効だが、サーバーが予期せぬ状況でそれを満たせなかった時に表示される。
理由
大抵のAPIプロバイダーは小さいサブセットHTTPステータスコードを使う。例えば、Googlo GData APIは10ステータスコードのみを使い、Netflixは9、Diggは8だけだ。もちろんそれらのレスポンスはbodyと追加情報を含む。そこには70HTTP以上のステータスコードがある。しかし、大抵のディベロッパーは、70全部を記憶しているわけではない。もし有名でないステータスコードを選ぶと、アプリケーションディベロッパーをアプリケーションの構築から遠ざけ、wikipediaから何を伝えようとしているか理解しなければいけない。 read more…
- レスポンスには総リソース数を提供する。
- limit と offset parameterを受け入れる。
- リソースが公開するデータ量も考慮される必要がある。APIコンシューマはいつも全てのリソースの表現が必要とは限らない。カンマで区切られたフィールドのリストを含むフィールドクエリparameterを使う。
GET /student?fields=id,name,age,class
- ページ作成、フィルタリング、およびソートは、すべてのリソースに対して最初からサポートする必要はない。フィルタリングとソートを提供するリソースを文書化する。
- Pagination, filtering, and sorting don’t need to be supported from start for all resources. Document those resources that offer filtering and sorting.
9.2 API security
基本的なセキュリティのベストプラクティスがある。
-セキュリティで保護された接続(HTTPS)を使用しない限り、基本認証はしようしない。認証トークンはURL: GET /users/123?token=asdf....
で送信してはいけない。
理由
トークンやユーザーID, passwordはネットワークを介してクリアテキスト(base 64でエンコードされるが、base64は可逆エンコードだ)として渡されるので、基本認証方式は安全ではない。read more…
- トークンはリクエストごとに認証ヘッダーを使って送信されなければいけない。
Authorization: Bearer xxxxxx, Extra yyyyy
- 認証コードは短命であるべきだ。
- 安全でないデータ交換を避けるため、すべてのHTTP リクエストに応答しないことで、non-TLSリクエストを拒否する。
403 Forbidden
によって、HTTP リクエストに応答する。 - レート制限を使うことを考える。なぜなら、1時間に数1000回のAPIコールをするボットの脅威から、APIを守るためだ。
- 適切にセットしたHTTPヘッダーは、ロックダウンし、ウェブアプリを安全することを助ける。Sread more…
- APIは受け取ったデータを標準フォームに変換するか、拒否する必要がある。悪い、もしくは欠落したデータからのエラーの詳細をもった400 Bad Requestを返す。
- REST APIと交換される全てのデータは、APIで検証されなければならない。
- JSONをシリアル化する。なぜなら、もしサーバー上でnode.jsを使っているなら、JSONエンコーダの懸念点は、ブラウザ内の任意のJSリモートコードの実行を妨げるからだ。
適切なJSONシリアライザーを使い、ブラウザ上でユーザー入力を実行することを妨げるため、ユーザーが入力したデータを適切に使うことが不可欠だ。 - 中身のタイプを検証する。また、
application/*json
(Content-Type header).を主に使う。
理由
例えば、application/x-www-form-urlencoded
mime タイプを受け入れることは、アタッカーがフォームを作り、簡単なPOSTリクエストをトリガーできる。サーバーはContent-typeを決して想定するべきでない。Content-typeヘッダーの欠如や、予期せぬContent-Typeヘッダーは、サーバーが4XX レスポンスでコンテンツを拒否するべきだ。
- For instance, accepting the
application/x-www-form-urlencoded
mime type allows the attacker to create a form and trigger a simple POST request. The server should never assume the Content-Type. A lack of Content-Type header or an unexpected Content-Type header should result in the server rejecting the content with a4XX
response. - API Security Checklist Projectを確認する。read more…
9.3 API documentation
- APIの README.md template のAPI Reference sectionに記入する。
- コードサンプルでAPI認証メソッドを記述する。
- リクエストタイプ(メソッド)を含むURL構成(pathだけ。root URLではない。)を説明する。
それぞれのエンドポイントについて
- URL Paramsが存在するなら、URLセクションで記載された名前にしたがって指定する。
Required: id=[integer]
Optional: photo_id=[alphanumeric]
- リクエストタイプがPOSTなら、動作サンプルを提供する。URL Params ruleはここでもまた適用される。セクションをOptionとRequiredに分ける。
- Responseに成功したら、ステータスコードはどうであるべきか、リターンデータはあるのか。これはコールバックが期待するものを知る必要がある場合に便利。
Code: 200 Content: { id : 12 }
- エラーレスポンスが出た。大抵のエンドポイントは、多くの失敗がありがち。権限のないアクセスから不正なparameterなどがある。それらは全てここでリスト化される。反復的に見えるが、仮定が作られないのに役立つ。
{
"code": 403,
"message" : "Authentication failed",
"description" : "Invalid username or password"
}
- APIデザインツールを使う。 API Blueprint and Swagger.などのいいオープンドキュメントツールがある。
10. Licensing
使用する権利を持つリソースを使っていることを確認する。もしライブラリをつかうなら、MIT、Apache, BSDを探すことをわすれないようにするが、もしそれらを修正するなら、ライセンスの詳細をみる。著作権で保護されている画像や動画が、法的問題を引き起こすかもしれない。
【わからなかったこと】
【感想】
ここで学んだことをやらかすと大きな問題になると思いました。