バックエンドプログラミング:ノード.js上のKoaフレームワーク

40694 ワード

1.紹介


2.作業環境の準備


1)ノードの取り付けを確認する

$ node --version

2)プロジェクトの作成

$ mkdir blog
$ cd blog
$ mkdir blog-backend
$ cd blog-backend
$ yarn init -y
この操作が完了すると、ディレクトリにパッケージされます.jsonファイルの作成が完了しました.
次のコマンドを使用して、ファイルの作成が正しいかどうかを確認できます.
$ cat package.json
Koa Webフレームワークをインストールします.
$ yarn add koa

3)ESLintとPrettierの設定

$ yarn add --dev eslint
$ yarn run eslint --init
$ yarn add eslint-config-prettier

3.Koaの基本的な使い方


1)オフセットサーバー

const Koa = require('koa');

const app = new Koa();

app.use((ctx) => {
  ctx.body = 'hello world';
});

app.listen(4000, () => {
  console.log('Listening to port 4000');
});
$ node src
既存のインデックス.jsファイルに次のコードを入力すると、サーバを4000ポート開き、Webブラウザを使用してhttp://localhose:4000/に接続します.

2.ミドルウェア


Koaアプリケーションはミドルウェアで構成されています.先ほどのコードで使用されたapp.use 함수は、アプリケーションにミドルウェア関数を登録します.
ミドルウェア関数は、次の構造で構成されています.
(ctx, next) => {
}
Koaのミドルウェア関数は2つのパラメータを受け入れる.ctxは、Webリクエストおよびレスポンスに関する情報を含むContextの略である.nextは、現在処理中のミドルウェアを呼び出す次のミドルウェアの関数です.ミドルウェアが登録されずnext関数が呼び出された場合、次のミドルウェアは処理されません.
以降、以下のミドルウェアを処理する必要のないルーティングミドルウェアを設定する場合は、nextを省略してミドルウェアを作成してください:ctx ⇒ { }.
中装はappuseを使用して登録順に処理します.
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
  console.log(ctx.url);
  console.log(1);
  next();
});

app.use((ctx, next) => {
  console.log(2);
  next();
});

app.use((ctx) => {
  ctx.body = 'hello world';
});

app.listen(4000, () => {
  console.log('Listening to port 4000');
});
実行中のサーバをシャットダウンして再実行すると、端末に次の結果が表示されます.
❯ node src
Listening to port 4000
/
1
2
/favicon.ico
1
2
ユーザーがWebページにアクセスすると、Chromeブラウザにサイトのアイコンファイル/faviconが表示されます.サーバにicoファイルを要求すると、結果に/パス、/faviconも表示されます.icoパスも表示されます.
最初のミドルウェアで呼び出されたnext関数に注釈を付けると、最初のミドルウェアのみが実行され、その下のすべてのミドルウェアが無視され、次の結果が得られます.
❯ node src
Listening to port 4000
/
1
/favicon.ico
1
これらのプロパティを使用して、authorized=1というクエリー・パラメータが要求パスに含まれている場合、後続のミドルウェアは保持されます.そうしないと、後続のミドルウェアは処理されません.
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
  console.log(ctx.url);
  console.log(1);
  if (ctx.query.authorized !== '1') {
    ctx.state = 401; // Unauthorized
    return;
  }
  next();
});

app.use((ctx, next) => {
  console.log(2);
  next();
});

app.use((ctx) => {
  ctx.body = 'hello world';
});

app.listen(4000, () => {
  console.log('Listening to port 4000');
});
クエリー・パラメータは文字列であるため、比較時に曲文字列として比較する必要があります.


ここでは,アドレスのクエリパラメータを用いて条件付きで処理するだけであるが,その後,WebリクエストのCookieやHeaderで処理することも可能である.

next gkatnsms Promiseを返します


next関数を呼び出してPromiseを返します.これはKoaとExpressの違いです.next関数が返すPromiseは、次の処理が必要なミドルウェアが完了してから完了する必要があります.
const Koa = require('koa');

const app = new Koa();

app.use((ctx, next) => {
  console.log(ctx.url);
  console.log(1);
  if (ctx.query.authorized !== '1') {
    ctx.state = 401; // Unauthorized
    return;
  }
  next().then(() => {
    console.log('END');
  });
});

app.use((ctx, next) => {
  console.log(2);
  next();
});

app.use((ctx) => {
  ctx.body = 'hello world';
});

app.listen(4000, () => {
  console.log('Listening to port 4000');
});
サーバーを再起動して再接続すると、ENDが表示されます.
❯ node src
Listening to port 4000
/
1
/?authorized=1
1
2
END

ルーティングパラメータとクエリー


パラメータとクエリーは、アドレスから特定の値を取得するために使用されますが、用途は少し異なります.
≪パラメータ|Parameters|oraolap≫:処理するタスクのカテゴリを受信するか、一意のIDまたは名前を使用して特定のデータを問合せます.
クエリー:オプションに関する情報を受信します.
// 파라미터
router.get('/about/:name?', ctx => {
    const { name } = ctx.params;
    // name의 존재 유무에 따라 다른 결과 출력
    ctx.body = name ? `${name}의 소개` : '소개';
});

// 쿼리
router.get('/posts', ctx => {
    const { id } = ctx.query;
    // id의 존재 유무에 따라 다른 결과 출력
    ctx.body = id ? `포스트 #${id}` : '포스트 아이디가 없습니다.';
});

REST API


Webアプリケーションを作成するには、データベースに情報を入力して取得する必要があります.クライアントがサーバにデータの表示、作成、削除、更新を要求すると、サーバは必要に応じてデータベースにアクセスしてタスクを処理します.
REST APIは、要求のタイプに応じて異なるHTTPメソッドを使用する.HTTPの方法はいろいろありますが、主に以下の方法を使用します.
HTTPメソッドのタイプ
ブログ記事用REST API

4.nodemonを使う


nodemonという名前のツールを使用すると、コードを変更するたびに自動的にサーバを再起動できます.
$ yarn add --dev nodemon

5.ルーティングモジュール化


プロジェクトの進行中に、複数のルーティングが作成されます.ただし、各ルーティングにインデックスを作成してください.jsファイルにすべてのルータを作成できません.複数のファイルに分けて作成、ロード、適用してください.
let postId = 1;     // id의 초깃값입니다.

// post 배열 초기 데이터
const posts = [
    {
        id: 1,
        title: '제목',
        body: '내용',
    },
];

/**
 * 포스트 작성
 * POST /api/posts
 * { title, body }
 */ 
export const write = ctx => {
    // REST API의 Request Body는 ctx.request.body에서 조회할 수 ㅣㅇㅆ습니다.
    const {title, body } = ctx.request.body;
    postId += 1;    // 기존 postId 값에 1을 더합니다.
    const post = { id: postId, title, body };
    posts.push(post);
    ctx.body = post;
};

/**
 * 포스트 목록 조회
 * GET /api/posts
 */
export const list = ctx => {
    ctx.body = posts;
};

/**
 * 특정 포스트 조회
 * GET /api/posts/:id
 */
export const read = ctx => {
    const { id } = ctx.params;
    // 주어진 id 값으로 포스트를 찾습니다.
    // 파라미터로 받아 온 값은 문자열 형식이므로 파라미터를 숫자로 변환하거나
    // 비교할 p.id 값을 문자열로 변경해야 합니다.
    const post = posts.find(p => p.id.toString() === id);
    // 포스트가 없으면 오류를 반환합니다.
    if (!post) {
        ctx.status = 404;
        ctx.body = {
            message: '포스트가 존재하지 않습니다.',
        };
        return;
    }
    ctx.body = post;
};

/**
 * 특정 포스트 제거
 * DELETE /api/posts/:id
 */
export const remove = ctx => {
    const { id } = ctx.params;
    // 해당 id를 가진 post가 몇 번째인지 확인합니다.
    const index = posts.findIndex(p => p.id.toString() === id);
    // 포스트가 없으면 오류를 반환합니다.
    if (index === -1) {
        ctx.status = 404;
        ctx.body = {
            message: '포스트가 존재하지 않습니다.',
        };
        return;
    }
    // index번째 아이템을 제거합니다.
    posts.splice(index, 1);
    ctx.status = 204;   // No Content
};

/**
 * 포스트 수정(교체)
 * PUT /api/posts/:id
 * { title, body }
 */
export const replace = ctx => {
    // PUT 메서드는 전체 포스트 정보를 입력하여 데이터를 통째로 교체할 때 사용합니다.
    const { id } = ctx.params;
    // 해당 id를 가진 post가 몇 번쩨인지 확인합니다.
    const index = posts.findImdex(p => p.id.toString() === id);
    // 포스트가 없으면 오류를 반환합니다.
    if (index === -1) {
        ctx.status = 404;
        ctx.body = {
            message: '포스트가존재하지 않습니다.',
        };
        return;
    }
    // 전체 객체를 덮어 씌웁니다.
    // 따라서 id를 제외한 기존 정보를 날리고, 객체를 새로 만듭니다.
    posts[index] = {
        id,
        ...ctx.request.body,
    };
    ctx.body = posts[index];
};

/**
 * 포스트 수정(특정 필드 변경)
 * PATCH /api/posts/:id
 * { title, body }
 */
export const update = ctx => {
    // PATCH 메서드는 주어진 필드만 교체합니다.
    const { id } = ctx.params;
    // 해당 id를 가진 post가 몇 번째인지 확인합니다.
    const index = posts.findIndex(p => p.id.toString() === id);
    // 포스트가 없으면 오류를 반환합니다.
    if (index === -1) {
        ctx.status = 404;
        ctx.body = {
            message: '포스트가 존재하지 않습니다.',
        };
        return;
    }
    // 기존 값에 정보를 덮어 씌웁니다.
    posts[index] = {
        ...posts[index],
        ...ctx.request.body,
    };
    ctx.body = posts[index];
};