Node.js、Express、およびExpressRouterを使用して非常に単純なRESTAPIを実装する

Aug 23 2020

Node.jsとExpressのロープを学ぶために、私は非常に単純なRESTAPIを実装しようとしています。APIは、それを行う代わりに何をすべきかを示しているので、フレームワークの構造に集中することができます。APIの要件は次のとおりです。

  • 質疑応答ゲームのモックAPI。
  • / qandaエンドポイント:すべての質問と回答のペアのリポジトリ。
  • / qanda / questionIdエンドポイント:特定の質問と回答のペア。
  • HTTP動詞GET、POST、PUT、DELETEを処理する必要があります。
  • HTTPリクエストの本文がJSONであると想定します。

これはすべて恣意的です。HTTPリクエストとレスポンスの処理と解析のコツをつかもうとしています。整理するために、ExpressRouterモジュールとNode.jsモジュールも使用しています。

これがindex.jsです

'use strict';
const express = require('express');

const qanda = require('./routes/qanda.js');

const port = 9999;
const app = express();

app.use('/qanda', qanda);

app
  .all('/', (req, res, nxt) => {
  res
    .status(200)
    .send('Welcome!');
  })
  .listen(port, () => {
    console.log(`Listening to localhost:${port}`);
  });

そしてここに./routes/qanda.jsがあります

'use strict';
const express = require('express');

const qandaRouter = express.Router();
qandaRouter.use(express.json());

qandaRouter
  .route('/')
  .get((req, res, nxt) => {
    res
      .status(200)
      .send('Sending all the qandas!');
  })
  .post((req, res, nxt) => {
    res
      .status(200)
      .send(`Adding ${req.body.q} = ${req.body.a}`); }) .put((req, res, nxt) => { res .status(405) .send('PUT not supported.'); }) .delete((req, res, nxt) => { res .status(200) .send('Deleting all qands!'); }); qandaRouter .route('/:qId') .get((req, res, nxt) => { res .status(200) .send(`Sending qanda ${req.params.qId}`);
  })
  .post((req, res, nxt) => {
    res
      .status(405)
      .send('POST not supported.');
  })
  .put((req, res, nxt) => {
    res
      .status(200)
      .send(`Updating ${req.params.qId} with ${req.body.q} = ${req.body.a}`); }) .delete((req, res, nxt) => { res .status(200) .send(`Deleting qanda ${req.params.qId}`);
  });

module.exports = qandaRouter;

皆様からのフィードバックをお待ちしております!スタイルからベストプラクティス、アンチパターンまで、考えられることは何でも大歓迎です!私はいくつかの特定の質問があります:

  • Expressでこのようなものを処理する通常の方法はメソッドチェーンですか?
  • メソッドチェーンスタイルは読みやすく、保守可能ですか?
  • これを達成するためのより簡潔な方法はありますか?
  • あなたは何を変えますか?

回答

6 KaterAkeren Aug 23 2020 at 20:44

あなたが書いたコードを調べた後、正しく行われていないことがいくつかわかりました。以下は私が強調したいくつかのことです:

  • コードベースの構造化は問題があるため、コードベースが大きくなった場合でも、保守と拡張が可能です。
  • RESTfulAPIの命名規則は受け入れられません。REST APIのエンドポイントには、リソース(名詞)のみが含まれ、アクションにはHTTPメソッド(動詞)を使用する必要があります。エンドポイントに/ qandasではなく/ qandaという名前を付けました。Hackernoonに投稿されたMaheshHaldarによるこのRESTfulAPI設計ガイドラインを読むことをお勧めします。これは開発者にとって素晴らしいリソースです。
  • 第三に、サーバーをExpressから分離していません。それらは両方とも一緒に結合されます。そうすることはベストプラクティスではありません。
  • APIが他のアプリケーションによって消費されている場合、いくつかの変更を加えてAPIをアップグレードすると、既存のサービス契約が破られることになります。これは、APIサービスを提供する多くのアプリケーションで認識されています。すべてのURLの前に常に/ api / v1 / usersを付けることをお勧めします。重大な更新があった場合は、新しいAPIセットにv2、v3、またはv1.XXという名前を付けることができます。それぞれ。

私の経験から、これは私がそれにアプローチする方法です:

  • まず、私は、というディレクトリが作成されますqanda-APIを、その中に、私は他と呼ばれるディレクトリを作成しますSRCと2つのファイルapp.jsとserver.jsをそれとルートディレクトリ内に存在するSRC
  • 次に、src内に、routesとcontrollersという2つのサブディレクトリを作成します。
  • 第三に、ターミナルから以下のコマンドを入力して、npmがインストールされたすべてのパッケージを追跡するプロジェクトディレクトリのルートにあるnpmレジストリを初期化します。

npm init

  • その後、同じ端末を介して使用する3つの依存関係をインストールしますが、今回はインターネットにアクセスできる必要があります。

npm install express dotenv morgan

  • 上記のプロセスが正常に実行されると、package.jsonというファイル内にインストールされたパッケージが表示されます。

手を汚してコーディングしてみましょう

  • まず、他の場所controllers / qandaController.jsという名前のファイルを作成して、ルートファイルにエクスポートされるqandaロジックを記述しましょう。
exports.getAllQandas = (req, res) => {
    res.status(200).json({
        status: 'success',
        message: 'Documments retrieved successfully',
        data: 'The data goes here from the data!'
    });
};

exports.getQanda = (req, res) => {
    res.status(200).json({
        status: 'success',
        message: 'Doc retrieved successfully',
        data: 'The data goes here from the data!'
    });
};

exports.createQanda = (req, res) => {
    res.status(201).json({
        status: 'success',
        message: 'Qanda created successfully',
        data: 'Return the created data here!'
    });
};

exports.updateQanda = (req, res) => {
    res.status(200).json({
        status: 'success',
        message: 'Doc updated successfully',
        data: 'The updated data goes here!'
    });
};

exports.deleteQanda = (req, res) => {
    res.status(200).json({
        status: 'success',
        message: 'Doc deleted!',
        data: 'Return the Deleted data'
    });
};
  • 今、私たちは私たちの作成することの時間qandaの中でルートをルート/ qandaRoutes.js。次に、以下のルートハンドラーにコントローラーロジックをインポートします。
const express = require('express');
/**
 * import the qanda controller
 */
const qandaController = require('./../controllers/qandaController');

const router = express.Router();

router
    .route('/')
    .get(qandaController.getAllQandas)
    .post(qandaController.createQanda);

router
    .route('/:id')
    .get(qandaController.getQanda)
    .patch(qandaController.updateQanda)
    .delete(qandaController.deleteQanda);

module.exports = router;
  • 以前に作成したapp.jsというファイルを他のファイルで開いて、インストールしたExpressを利用してみましょう。このファイルの内容はエクスプレス専用であり、サーバーにエクスポートされます。
const express = require('express');
const morgan = require('morgan');

const qandaRouter = require('./routes/qandaRoutes');

const app = express();
    
if (process.env.NODE_ENV === 'development') app.use(morgan('dev'));

// ROUTES
app.use('/api/v1/qandas', qandaRouter);
    
/*
 ** HANDLING UNHANDLED ROUTES
 */
app.all('*', (req, res, next) => {
    res.status(404).json({
        status: 'fail',
            message: `Can't find ${req.originalUrl} on this Server!`
    });
});
   
module.exports = app;
  • アプリケーションへのエントリポイントとなるサーバーを作成しましょう。これは実際の実行が発生し、エクスポートされたapp.jsがcreateServer()関数に引数として挿入されることで使用されます。
require('dotenv').config({ path: '.env' });
const http = require('http');

const app = require('./app');

const port = process.env.PORT || 5000;

const server = http.createServer(app);

server.listen(port, () => console.log(`App running on port ${port}`));

結論

コードを作成するときは常に関心の分離を行い、長期にわたって保守可能でスケーラブルなクリーンなコードベースを適切に用意することを強くお勧めします。API設計に関しては、コード編成にはさらに多くのことがあります。その1つは、DRYの原則(Do n't Repeat Yourself)です。Node.JSでのAPI設計について詳しく知りたい場合は、Jonasによるこのコースを受講することをお勧めします。彼は抽象的な概念をわかりやすく説明し、コアにベストプラクティスを教えました。:私はGithubの中にAPIの設計プロジェクトで、この答えを包みましたAPIや観光API。必要に応じて、自由に複製または変更してください。