apeescape2.com
  • メイン
  • Uxデザイン
  • エンジニアリング管理
  • 技術
  • トレンド
バックエンド

Node.js / TypeScript REST APIの構築、パート1:Express.js

Node.jsでRESTAPIを作成するにはどうすればよいですか?

REST APIのバックエンドを構築する場合、多くの場合、Express.jsがNode.jsフレームワークの最初の選択肢です。静的HTMLとテンプレートの作成もサポートしていますが、このシリーズでは、TypeScriptを使用したバックエンド開発に焦点を当てます。結果のRESTAPIは、フロントエンドフレームワークまたは外部バックエンドサービスがクエリできるものになります。

あなたは必要になるでしょう:

  • JavaScriptとTypeScriptの基本的な知識
  • Node.jsの基本的な知識
  • RESTアーキテクチャの基本的な知識(cf. このセクション 必要に応じて、以前のREST API記事の)
  • Node.jsの準備ができたインストール(できればバージョン14以降)

ターミナル(またはコマンドプロンプト)で、プロジェクト用のフォルダーを作成します。そのフォルダーから、npm initを実行します。 それが作成されます 必要な基本的なNode.jsプロジェクトファイルのいくつか。



次に、Express.jsフレームワークといくつかの便利なライブラリを追加します。

npm install --save express debug winston express-winston cors

これらのライブラリには十分な理由があります Node.js開発者 お気に入り:

  • debug console.log()の呼び出しを回避するために使用するモジュールですアプリケーションの開発中。このようにして、トラブルシューティング中にデバッグステートメントを簡単にフィルタリングできます。手動で削除する代わりに、本番環境で完全にオフにすることもできます。
  • winston APIへのリクエストと、返されたレスポンス(およびエラー)をログに記録する責任があります。 express-winston Express.jsと直接統合されるため、すべての標準API関連winstonロギングコードはすでに実行されています。
  • cors Express.jsミドルウェアの一部であり、これを有効にすることができます クロスオリジンリソースシェアリング 。これがないと、APIは、バックエンドとまったく同じサブドメインから提供されるフロントエンドからのみ使用できます。

バックエンドは、実行時にこれらのパッケージを使用します。しかし、いくつかをインストールする必要もあります 開発 TypeScript構成の依存関係。そのために、以下を実行します。

npm install --save-dev @types/cors @types/express @types/debug source-map-support tslint typescript

これらの依存関係は、Express.jsやその他の依存関係で使用されるタイプとともに、アプリ自体のコードでTypeScriptを有効にするために必要です。これにより、コーディング中に一部の関数メソッドを自動的に完了することができるため、WebStormやVSCodeなどのIDEを使用しているときに多くの時間を節約できます。

ブルームバーグターミナルとは

package.jsonの最終的な依存関係次のようになります。

'dependencies': { 'debug': '^4.2.0', 'express': '^4.17.1', 'express-winston': '^4.0.5', 'winston': '^3.3.3', 'cors': '^2.8.5' }, 'devDependencies': { '@types/cors': '^2.8.7', '@types/debug': '^4.1.5', '@types/express': '^4.17.2', 'source-map-support': '^0.5.16', 'tslint': '^6.0.0', 'typescript': '^3.7.5' }

必要な依存関係がすべてインストールされたので、独自のコードの作成を始めましょう。

TypeScript RESTAPIプロジェクト構造

このチュートリアルでは、次の3つのファイルのみを作成します。

  1. ./app.ts
  2. ./common/common.routes.config.ts
  3. ./users/users.routes.config.ts

プロジェクト構造の2つのフォルダー(commonとusers)の背後にある考え方は、独自の責任を持つ個々のモジュールを持つことです。この意味で、最終的には、モジュールごとに次の一部またはすべてを使用することになります。

  • ルート構成 APIが処理できるリクエストを定義する
  • サービス データベースモデルへの接続、クエリの実行、特定のリクエストに必要な外部サービスへの接続などのタスク
  • ミドルウェア ルートの最終コントローラーがその詳細を処理する前に、特定の要求検証を実行するため
  • モデル 特定のデータベーススキーマに一致するデータモデルを定義し、データの保存と取得を容易にします
  • コントローラー 最終的に(ミドルウェアの後で)ルート要求を処理し、必要に応じて上記のサービス関数を呼び出し、クライアントに応答するコードからルート構成を分離するため

このフォルダ構造は、このチュートリアルシリーズの残りの部分の初期の開始点であり、練習を開始するのに十分です。

TypeScriptの一般的なルートファイル

commonでフォルダ、common.routes.config.tsを作成しましょう次のようなファイル:

import express from 'express'; export class CommonRoutesConfig { app: express.Application; name: string; constructor(app: express.Application, name: string) { this.app = app; this.name = name; } getName() { return this.name; } }

ここでルートを作成する方法はオプションです。しかし、TypeScriptを使用しているため、ルートシナリオは、extendsで継承を使用する練習をする機会です。キーワード。これについては後ほど説明します。このプロジェクトでは、すべてのルートファイルの動作は同じです。名前(デバッグ目的で使用します)とメインのExpress.jsへのアクセスがありますApplicationオブジェクト。

これで、ユーザールートファイルの作成を開始できます。 usersでフォルダ、作成しましょうusers.routes.config.ts次のようにコーディングを開始します。

ノードjsが使用される理由
import {CommonRoutesConfig} from '../common/common.routes.config'; import express from 'express'; export class UsersRoutes extends CommonRoutesConfig { constructor(app: express.Application) { super(app, 'UsersRoutes'); } }

ここでは、CommonRoutesConfigをインポートしていますクラスとそれをUsersRoutesと呼ばれる新しいクラスに拡張します。コンストラクターを使用して、アプリ(メインのexpress.Applicationオブジェクト)と名前UsersRoutesをCommonRoutesConfigのコンストラクターに送信します。

この例は非常に単純ですが、スケーリングして複数のルートファイルを作成する場合、これは重複コードを回避するのに役立ちます。

このファイルに、ロギングなどの新しい機能を追加するとします。必要なフィールドをCommonRoutesConfigに追加できますクラス、そしてCommonRoutesConfigを拡張するすべてのルートそれにアクセスできるようになります。

クラス間で同様の機能を実現するためのTypeScript抽象関数の使用

いくつかの機能が必要な場合はどうなりますか 同様 これらのクラス間(APIエンドポイントの構成など)ですが、クラスごとに異なる実装が必要ですか? 1つのオプションは、と呼ばれるTypeScript機能を使用することです。 抽象化 。

UsersRoutesという非常に単純な抽象関数を作成しましょう。クラス(および将来のルーティングクラス)はCommonRoutesConfigから継承します。すべてのルートにconfigureRoutes()という名前の関数(共通のコンストラクターから呼び出すことができるようにする)を強制したいとします。ここで、各ルーティングクラスのリソースのエンドポイントを宣言します。

これを行うために、common.routes.config.tsに3つの簡単なものを追加します。

  1. キーワードabstract classへline、このクラスの抽象化を有効にします。
  2. クラスの最後にある新しい関数宣言abstract configureRoutes(): express.Application;。これにより、CommonRoutesConfigを拡張するクラスが強制されます。その署名に一致する実装を提供します。一致しない場合、TypeScriptコンパイラはエラーをスローします。
  3. this.configureRoutes();への呼び出しコンストラクターの最後に、この関数が存在することを確認できるためです。

結果:

import express from 'express'; export abstract class CommonRoutesConfig { app: express.Application; name: string; constructor(app: express.Application, name: string) { this.app = app; this.name = name; this.configureRoutes(); } getName() { return this.name; } abstract configureRoutes(): express.Application; }

これで、CommonRoutesConfigを拡張するクラスconfigureRoutes()という関数が必要ですexpress.Applicationを返しますオブジェクト。つまり、users.routes.config.ts更新が必要:

import {CommonRoutesConfig} from '../common/common.routes.config'; import express from 'express'; export class UsersRoutes extends CommonRoutesConfig { constructor(app: express.Application) { super(app, 'UsersRoutes'); } configureRoutes() { // (we'll add the actual route configuration here next) return this.app; } }

私たちが作ったものの要約として:

最初にcommon.routes.configをインポートしますファイル、次にexpressモジュール。次に、UserRoutesを定義しますクラス、CommonRoutesConfigを拡張したいと言っています基本クラス。これは、configureRoutes()を実装することを約束することを意味します。

CommonRoutesConfigに情報を送信するにはクラスでは、constructorを使用していますクラスの。 express.Applicationを受け取ることを期待していますオブジェクト。次のステップでさらに詳しく説明します。 super()を使用して、CommonRoutesConfigのコンストラクターに、アプリケーションとルートの名前(このシナリオではUsersRoutes)を渡します。 (super()は、configureRoutes()の実装を呼び出します。)

ユーザーエンドポイントのExpress.jsルートの構成

configureRoutes()関数は、RESTAPIのユーザー用のエンドポイントを作成する場所です。そこで、使用します 応用 そしてその ルート Express.jsの機能。

app.route()を使用する際のアイデア機能は、コードの重複を回避することです。これは、明確に定義されたリソースを使用してRESTAPIを作成しているため簡単です。このチュートリアルの主なリソースは ユーザー 。このシナリオには2つのケースがあります。

  • API呼び出し元が新しいユーザーを作成したり、既存のすべてのユーザーを一覧表示したりする場合、エンドポイントには最初はusersが必要です。要求されたパスの最後。 (この記事では、クエリのフィルタリング、ページ付け、またはその他のそのようなクエリについては説明しません。)
  • 呼び出し元が特定のユーザーレコードに固有の処理を実行する場合、リクエストのリソースパスはパターンusers/:userIdに従います。

方法.route() Express.jsで動作するため、エレガントなチェーンでHTTP動詞を処理できます。これは、.get()、.post()などがすべてIRouteの同じインスタンスを返すためです。その最初の.route()呼び出しは行います。最終的な構成は次のようになります。

configureRoutes() { this.app.route(`/users`) .get((req: express.Request, res: express.Response) => { res.status(200).send(`List of users`); }) .post((req: express.Request, res: express.Response) => { res.status(200).send(`Post to users`); }); this.app.route(`/users/:userId`) .all((req: express.Request, res: express.Response, next: express.NextFunction) => { // this middleware function runs before any request to /users/:userId // but it doesn't accomplish anything just yet--- // it simply passes control to the next applicable function below using next() next(); }) .get((req: express.Request, res: express.Response) => { res.status(200).send(`GET requested for id ${req.params.userId}`); }) .put((req: express.Request, res: express.Response) => { res.status(200).send(`PUT requested for id ${req.params.userId}`); }) .patch((req: express.Request, res: express.Response) => { res.status(200).send(`PATCH requested for id ${req.params.userId}`); }) .delete((req: express.Request, res: express.Response) => { res.status(200).send(`DELETE requested for id ${req.params.userId}`); }); return this.app; }

上記のコードにより、RESTAPIクライアントはusersを呼び出すことができます。 POSTのエンドポイントまたはGETリクエスト。同様に、クライアントは私たちの/users/:userIdを呼び出すことができますGET、PUT、PATCH、またはDELETEのエンドポイントリクエスト。

良いランディングページをデザインする方法

ただし、/users/:userIdについては、all()を使用した汎用ミドルウェアも追加しました。 get()、put()、patch()、またはdelete()のいずれかの前に実行される関数機能。この機能は、(シリーズの後半で)認証されたユーザーのみがアクセスすることを目的としたルートを作成する場合に役立ちます。

.all()でお気づきかもしれません関数は、他のミドルウェアと同様に、Request、Response、およびNextFunctionの3種類のフィールドがあります。

  • ザ・ リクエスト Express.jsが処理されるHTTPリクエストを表す方法です。このタイプは、 ネイティブNode.js リクエストの種類。
  • ザ・ 応答 同様に、Express.jsがHTTP応答を表す方法であり、ここでも ネイティブNode.js 応答タイプ。
  • それほど重要ではありませんが、NextFunctionコールバック関数として機能し、制御が他のミドルウェア関数を通過できるようにします。その過程で、コントローラーが最終的にリクエスターに応答を送り返す前に、すべてのミドルウェアが同じ要求オブジェクトと応答オブジェクトを共有します。

Node.jsエントリポイントファイルapp.ts

いくつかの基本的なルートスケルトンを構成したので、アプリケーションのエントリポイントの構成を開始します。 app.tsを作成しましょうプロジェクトフォルダのルートにあるファイルを次のコードで開始します。

import express from 'express'; import * as http from 'http'; import * as bodyparser from 'body-parser'; import * as winston from 'winston'; import * as expressWinston from 'express-winston'; import cors from 'cors'; import {CommonRoutesConfig} from './common/common.routes.config'; import {UsersRoutes} from './users/users.routes.config'; import debug from 'debug';

記事のこの時点では、これらのインポートのうち2つだけが新しいものです。

  • http Node.jsネイティブモジュールです。 Express.jsアプリケーションを起動する必要があります。
  • body-parser Express.jsに付属するミドルウェアです。制御が独自のリクエストハンドラに移る前に、リクエストを(この場合はJSONとして)解析します。

ファイルをインポートしたので、使用する変数の宣言を開始します。

const app: express.Application = express(); const server: http.Server = http.createServer(app); const port: Number = 3000; const routes: Array = []; const debugLog: debug.IDebugger = debug('app');

express()関数は、コード全体に渡すメインのExpress.jsアプリケーションオブジェクトを返します。これは、http.Serverへの追加から始まります。オブジェクト。 (http.Serverを構成した後、express.Applicationを開始する必要があります。)

通常、アプリのフロントエンドに使用されるため、標準のポート80(HTTP)または443(HTTPS)ではなくポート3000でリッスンします。

なぜポート3000?

ポートを3000にするという規則はありません。指定されていない場合は、 任意のポート が割り当てられますが、Node.jsとExpress.jsの両方のドキュメントの例では3000が使用されているため、ここでは伝統を継続します。

Node.jsはフロントエンドとポートを共有できますか?

バックエンドが標準ポートでの要求に応答するようにしたい場合でも、カスタムポートでローカルに実行できます。これには、 リバースプロキシ 特定のドメインまたはサブドメインを持つポート80または443でリクエストを受信します。次に、それらを内部ポート3000にリダイレクトします。

routes配列は、以下に示すように、デバッグの目的でルートファイルを追跡します。

最後に、debugLog最終的にはconsole.logと同様の関数になりますが、より優れています。ファイル/モジュールコンテキストと呼びたいものに自動的にスコープされるため、微調整が簡単です。 (この場合、文字列でdebug()コンストラクターに渡したときに「アプリ」と呼びました。)

リフトvsユーバービジネスモデル

これで、すべてのExpress.jsミドルウェアモジュールとAPIのルートを構成する準備が整いました。

// here we are adding middleware to parse all incoming requests as JSON app.use(bodyparser.json()); // here we are adding middleware to allow cross-origin requests app.use(cors()); // here we are configuring the expressWinston logging middleware, // which will automatically log all HTTP requests handled by Express.js app.use(expressWinston.logger({ transports: [ new winston.transports.Console() ], format: winston.format.combine( winston.format.colorize(), winston.format.json() ) })); // here we are adding the UserRoutes to our array, // after sending the Express.js application object to have the routes added to our app! routes.push(new UsersRoutes(app)); // here we are configuring the expressWinston error-logging middleware, // which doesn't *handle* errors per se, but does *log* them app.use(expressWinston.errorLogger({ transports: [ new winston.transports.Console() ], format: winston.format.combine( winston.format.colorize(), winston.format.json() ) })); // this is a simple route to make sure everything is working properly app.get('/', (req: express.Request, res: express.Response) => { res.status(200).send(`Server up and running!`) });

expressWinston.errorLoggerに気づいたかもしれません設定されています 後 ルートを定義します。これは間違いではありません!として Express-Winstonのドキュメント 状態:

ロガーは、エクスプレスルーター(app.router)の後、およびカスタムエラーハンドラー(express.handler)の前に追加する必要があります。

最後にそして最も重要なこと:

server.listen(port, () => { debugLog(`Server running at http://localhost:${port}`); routes.forEach((route: CommonRoutesConfig) => { debugLog(`Routes configured for ${route.getName()}`); }); });

これにより、実際にサーバーが起動します。開始されると、Node.jsはコールバック関数を実行します。この関数は、実行中であることを報告し、その後に構成したすべてのルートの名前が続きます。これまでのところ、UsersRoutesだけです。

更新中package.json TypeScriptをJavaScriptにトランスパイルしてアプリを実行する

スケルトンを実行する準備ができたので、最初にTypeScriptトランスパイルを有効にするための定型的な構成が必要です。ファイルを追加しましょうtsconfig.jsonプロジェクトルート内:

{ 'compilerOptions': { 'target': 'es2016', 'module': 'commonjs', 'outDir': './dist', 'strict': true, 'esModuleInterop': true, 'inlineSourceMap': true } }

次に、最後の仕上げをpackage.jsonに追加する必要があります。次のスクリプトの形式で:

'scripts': { 'start': 'tsc && node ./dist/app.js', 'debug': 'export DEBUG=* && npm run start', 'test': 'echo 'Error: no test specified' && exit 1' },

testスクリプトは、シリーズの後半で置き換えるプレースホルダーです。

ザ・ tsc startでスクリプトはTypeScriptに属しています。 TypeScriptコードをJavaScriptにトランスパイルし、それをdistに出力します。フォルダ。次に、ビルドバージョンをnode ./dist/app.jsで実行します。

debugスクリプトはstartを呼び出しますスクリプトですが、最初にDEBUGを定義します環境変数。これには、すべてのdebugLog()を有効にする効果があります。ステートメント(および、Express.js自体からの同様のステートメント。これは、同じdebugモジュールを使用します)を使用して、有用な詳細を端末に出力します。 npm start。

実行してみてくださいnpm run debugあなた自身、そしてその後、それをnpm startと比較してくださいコンソール出力がどのように変化するかを確認します。

ヒント:デバッグ出力をapp.tsに制限できますファイル独自のdebugLog() DEBUG=appを使用するステートメントDEBUG=*の代わりに。 debugモジュールは一般的に非常に柔軟性があり、この機能は 例外ではありません 。

Windowsユーザーはおそらくexportを変更する必要があります〜SET export以降MacとLinuxでどのように機能するかです。プロジェクトが複数の開発環境をサポートする必要がある場合は、 cross-envパッケージ ここで簡単な解決策を提供します。

LiveExpress.jsバックエンドのテスト

npm run debugを使用またはnpm start引き続き、REST APIはポート3000でリクエストを処理する準備が整います。この時点で、cURLを使用できます。 郵便配達員 、 不眠症 など、バックエンドをテストします。

ユーザーリソースのスケルトンのみを作成したため、本文なしでリクエストを送信するだけで、すべてが期待どおりに機能していることを確認できます。例えば:

curl --location --request GET 'localhost:3000/users/12345'

バックエンドは回答を返送する必要がありますGET requested for id 12345。

POST ingについて:

curl --location --request POST 'localhost:3000/users' --data-raw ''

これと、スケルトンを作成した他のすべてのタイプのリクエストは、非常によく似ています。

TypeScriptを使用した迅速なNode.jsRESTAPI開発の準備ができています

この記事では、プロジェクトを最初から構成し、Express.jsフレームワークの基本に飛び込むことで、RESTAPIの作成を開始しました。次に、UsersRoutesConfigを使用してパターンを作成することにより、TypeScriptをマスターするための最初の一歩を踏み出しました。 CommonRoutesConfigを拡張します。これは、このシリーズの次の記事で再利用するパターンです。 app.tsを構成して終了しました新しいルートとpackage.jsonを使用するためのエントリポイントアプリケーションをビルドして実行するためのスクリプトを使用します。

しかし、Express.jsとTypeScriptで作成されたRESTAPIの基本でさえかなり複雑です。に 次の部分 このシリーズでは、ユーザーリソース用の適切なコントローラーの作成に焦点を当て、サービス、ミドルウェア、コントローラー、およびモデルのいくつかの有用なパターンを掘り下げます。

プロジェクト全体が利用可能です GitHubで 、およびこの記事の終わりのコードはtoptal-article-01にあります。ブランチ。

基本を理解する

Node.jsでTypeScriptを使用できますか?

絶対に!人気のあるnpmパッケージ(Express.jsを含む)には、対応するTypeScriptタイプ定義ファイルがあるのが非常に一般的です。これは、Node.js自体に加えて、デバッグパッケージなどの含まれているサブコンポーネントにも当てはまります。

Node.jsはRESTAPIに適していますか?

はい。 Node.jsを単独で使用して本番環境に対応したRESTAPIを作成できます。また、Express.jsのように、避けられない定型文を減らすための一般的なフレームワークもいくつかあります。

TypeScriptを学ぶのは難しいですか?

いいえ、最新のJavaScriptのバックグラウンドを持つ人のためにTypeScriptの学習を開始することは難しくありません。オブジェクト指向プログラミングの経験がある人にとってはさらに簡単です。ただし、他のスキルと同様に、TypeScriptのニュアンスとベストプラクティスをすべて習得するには時間がかかります。

go vs nodejsのパフォーマンス

TypeScriptを使用する必要がありますか?

プロジェクトによって異なりますが、Node.jsプログラミングには絶対にお勧めです。これは、バックエンドで実際の問題ドメインをモデル化するためのより表現力豊かな言語です。これにより、コードが読みやすくなり、バグの可能性が減少します。

TypeScriptは何に使用されますか?

TypeScriptは、JavaScriptが見つかる場所ならどこでも使用されますが、特に大規模なアプリケーションに適しています。 JavaScriptをベースとして使用し、静的型付けを追加し、オブジェクト指向プログラミング(OOP)パラダイムのサポートを大幅に向上させます。これにより、より高度な開発とデバッグのエクスペリエンスがサポートされます。

ブログを高コンバージョンファネルに変えるための5ステップのプロセス

Uxデザイン

ブログを高コンバージョンファネルに変えるための5ステップのプロセス
Power Pivot for Excelチュートリアル:最もよく使用されるケースと例

Power Pivot for Excelチュートリアル:最もよく使用されるケースと例

財務プロセス

人気の投稿
してはいけないこと–悪い製品デザインの美しさ(インフォグラフィック付き)
してはいけないこと–悪い製品デザインの美しさ(インフォグラフィック付き)
RESTアシュアードvs。 JMeter:RESTテストツールの比較
RESTアシュアードvs。 JMeter:RESTテストツールの比較
多言語アプリを構築する方法:PHPとGettextを使用したデモ
多言語アプリを構築する方法:PHPとGettextを使用したデモ
伝統的な雇用の終焉—他のギグエコノミー
伝統的な雇用の終焉—他のギグエコノミー
データエンコーディング:PHPおよびMySQLのUTF-8ガイド
データエンコーディング:PHPおよびMySQLのUTF-8ガイド
 
ゲシュタルトの設計原則を探る
ゲシュタルトの設計原則を探る
マネジメントバイアウトプロセスを成功させるには何が必要ですか?
マネジメントバイアウトプロセスを成功させるには何が必要ですか?
ApeeScapeは、世界中の開発者の上位3%を提供し、企業がエリート技術人材の不足に対処できるよう支援します
ApeeScapeは、世界中の開発者の上位3%を提供し、企業がエリート技術人材の不足に対処できるよう支援します
Gulpを使用したJavaScript自動化の概要
Gulpを使用したJavaScript自動化の概要
Android開発者を引き締め、新しいAndroidコンパイラが登場します
Android開発者を引き締め、新しいAndroidコンパイラが登場します
人気の投稿
  • 需要の価格弾力性の推定
  • 次のルールのうち、資本予算分析に正しいものはどれですか?
  • Webフォントと印刷フォント
  • メッセージに応答する不和ボット
  • nodejsエラー処理のベストプラクティス
カテゴリー
設計プロセス ライフスタイル エンジニアリング管理 アジャイル Uxデザイン プロセスとツール 革新 収益性と効率性 モバイル バックエンド

© 2021 | 全著作権所有

apeescape2.com