Casual Developers Note

エンジニアやデザイナー向けの技術情報・英語学習情報・海外留学情報・海外旅行情報を提供中。世界を旅して人生を楽しもう。

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • お問い合わせ
現在の場所:ホーム / アーカイブrestify

2018年10月15日 By KD コメントを書く

Expressはもう飽きた!もう一つのNodeJSフレームワークでAPIを作ろう(Restify編)

Expressはもう飽きた!もう一つのNodeJSフレームワークでAPIを作ろう(Restify編)

NodeJSのフレームワークと言えばExpressですが、毎回同じフレームワークを使っていては飽きてしまいます。今回は、もう一つのNodeJSフレームワークであるRestifyを使ってAPIを作ってみましょう。

はじめに

Restifyは、Production Ready、Debuggable、Semantically Correctを掲げているNodeJSのフレームワークです。簡単に言うとExpressの軽量版のようなフレームワークです。NPM、Netflix、Pinterestなどで利用されています。

それでは、始めましょう。

前提

以下がインストールされている必要があります。

  • NodeJS v10
  • Yarn
  • Docker

詳しくは、「環境」を参照してください。

MongoDBの準備

Dockerで一時的にMongoDBを用意します。

$ docker container run -d --rm --name mongo-docker -p 27018:27017 mongo:3.6.3
$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                      NAMES
837afddb96f3        mongo:3.6.3         "docker-entrypoint.s…"   6 seconds ago       Up 5 seconds        0.0.0.0:27018->27017/tcp   mongo-docker
$ mongo --port 27018
MongoDB shell version v4.0.2
connecting to: mongodb://127.0.0.1:27018/
MongoDB server version: 3.6.3
...
> exit
bye

ローカルでMongoDBを起動している人もいると思うので、ポートは27018としています。

API作成

さっそくAPIを作っていきましょう。

ベースプロジェクトの作成

今回は、本をCRUDするAPIを作ります。まずはベースのプロジェクトを作りましょう。

$ mkdir nodejs-restify-rest-api
$ cd nodejs-restify-rest-api/
$ yarn init -y
$ yarn add restify restify-errors mongoose joi
$ touch app.js
$ mkdir utils
$ touch utils/respond.js
$ mkdir models
$ touch models/Book.js
$ tree -L 2 -I node_modules
.
├── app.js
├── models
│   └── Book.js
├── package.json
├── utils
│   └── respond.js
└── yarn.lock

雛形ができました。

APIの実装

実装しましょう

Book.js

const mongoose = require('mongoose');

const { Schema } = mongoose;

const BookSchema = new Schema({
  isbn: String,
  title: String,
  author: String,
  pages: Number,
});

const Book = mongoose.model('books', BookSchema);

module.exports = Book;

respond.js

const respond = (res, next, data, statusCode) => {
  res.header('content-type', 'application/json');
  res.send(statusCode, data);
  return next();
};

module.exports = respond;

app.js

動作確認

それでは、Curlを使って動作確認をしてみましょう。

正しく動いていますね。

バリデーションを追加する

最後に、バリデーションを追加していきましょう。

バリデーションの実装

Restifyのバリデーションのライブラリはあまりメンテナンスがされていないものが多いので、Joiを使って実装することにします。

app.js

const restify = require('restify');
const {
BadRequestError,
NotFoundError,
InternalError,
} = require('restify-errors');
const Joi = require('joi');
const mongoose = require('mongoose');
const respond = require('./utils/respond');
const Book = require('./models/Book');
const PORT = process.env.PORT || 3000;
const MONGO_URL = 'mongodb://localhost:27018/testdb';
mongoose.connect(
MONGO_URL,
{ useNewUrlParser: true },
);
const server = restify.createServer();
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser());
server.get('/books', async (req, res, next) => {
try {
const books = await Book.find({});
return respond(res, next, books, 200);
} catch (error) {
return next(
new InternalError({
toJSON: () => ({
errors: [{ message: 'Database Error' }],
}),
}),
);
}
});
server.get('/books/:id', async (req, res, next) => {
const schema = Joi.object().keys({
id: Joi.string()
.length(24)
.required(),
});
const result = Joi.validate(req.params, schema);
if (result.error) {
return next(
new BadRequestError({
toJSON: () => ({
errors: result.error.details,
}),
}),
);
}
try {
const book = await Book.findById(req.params.id);
if (!book) {
return next(
new NotFoundError({
toJSON: () => ({
errors: [{ message: 'The book NOT found' }],
}),
}),
);
}
return respond(res, next, book, 200);
} catch (error) {
return next(
new InternalError({
toJSON: () => ({
errors: [{ message: 'Database Error' }],
}),
}),
);
}
});
server.post('/books', async (req, res, next) => {
const schema = Joi.object().keys({
isbn: Joi.string()
.length(13)
.required(),
title: Joi.string().required(),
author: Joi.string().required(),
pages: Joi.number().required(),
});
const result = Joi.validate(req.body, schema);
if (result.error) {
return next(
new BadRequestError({
toJSON: () => ({
errors: result.error.details,
}),
}),
);
}
try {
const book = new Book();
book.isbn = req.body.isbn;
book.title = req.body.title;
book.author = req.body.author;
book.pages = req.body.pages;
await book.save();
return respond(res, next, book, 200);
} catch (error) {
return next(
new InternalError({
toJSON: () => ({
errors: [{ message: 'Database Error' }],
}),
}),
);
}
});
server.put('/books/:id', async (req, res, next) => {
const schema = Joi.object().keys({
id: Joi.string()
.length(24)
.required(),
isbn: Joi.string().length(13),
title: Joi.string(),
author: Joi.string(),
pages: Joi.number(),
});
const result = Joi.validate(Object.assign(req.params, req.body), schema);
if (result.error) {
return next(
new BadRequestError({
toJSON: () => ({
errors: result.error.details,
}),
}),
);
}
try {
const book = await Book.findById(req.params.id);
if (!book) {
return next(
new NotFoundError({
toJSON: () => ({
errors: [{ message: 'The book NOT found' }],
}),
}),
);
}
Object.assign(book, req.body);
await book.save();
return respond(res, next, book, 200);
} catch (error) {
return next(
new InternalError({
toJSON: () => ({
errors: [{ message: 'Database Error' }],
}),
}),
);
}
});
server.del('/books/:id', async (req, res, next) => {
const schema = Joi.object().keys({
id: Joi.string()
.length(24)
.required(),
});
const result = Joi.validate(req.params, schema);
if (result.error) {
return next(
new BadRequestError({
toJSON: () => ({
errors: result.error.details,
}),
}),
);
}
try {
const book = await Book.findById(req.params.id);
if (!book) {
return next(
new NotFoundError({
toJSON: () => ({
errors: [{ message: 'The book NOT found' }],
}),
}),
);
}
book.remove();
return respond(res, next, book, 200);
} catch (error) {
return next(
new InternalError({
toJSON: () => ({
errors: [{ message: 'Database Error' }],
}),
}),
);
}
});
server.listen(PORT, () => {
console.log(`Server up on ${PORT}...`);
});

完成です。

動作確認

少しだけバリデーションを確認しましょう。

$ curl -v -H "Accept:application/json" http://localhost:3000/books/12345 | jq
{
"errors": [
{
"message": "\"id\" length must be 24 characters long",
"path": [
"id"
],
"type": "string.length",
"context": {
"limit": 24,
"value": "12345",
"key": "id",
"label": "id"
}
}
]
}

よさそうですね。

最後に

いかがでしたか?Expressだけでなく、RestifyでもAPIが作れるようになったことでしょう。それでは。

環境

  • NodeJS: v10.11.0
  • Yarn: 1.9.4
  • Docker: Docker version 18.06.1-ce, build e68fc7a
  • MongoDB: 3.6.3
  • restify: 7.2.1
  • restify-errors: 6.1.1
  • mongoose: 5.3.0
  • joi: 13.7.0
  • curl: 7.54.0
  • jq: jq-1.5

カテゴリ : 技術 Tips & Tutorials タグ : nodejs, rest-api, restify

ブログ更新情報や海外の関連情報などを配信する無料メルマガ

Sponsored Links

About Author

KD

世界を旅し日本を愛するエンジニア。大学でコンピュータサイエンスの楽しさを学び、日本の大手IT企業で働く中で、新しい技術やスケールするビジネスが北米にある事に気づく。世界に挑戦するための最大の壁が英語であったため、フィリピン留学およびカナダ留学を経て英語を上達させた。現在は日本在住でエンジニアとして働きつつ、次の挑戦に備えて世界の動向を注視している。挑戦に終わりはない。このブログでは、エンジニアやデザイナー向けの技術情報から、海外に留学したい人向けの留学情報、海外に興味がある人向けの海外旅行情報など、有益な情報を提供しています。

https://casualdevelopers.com/

最近の投稿

  • 2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年JS周辺のバックエンド寄りの注目技術!ネクストNodeJSの「Deno」と分散型パッケージレジストリの「Entropic」の紹介

    2020年1月13日
  • 今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    今さら聞けないJavaによる関数型プログラミング入門 ~ラムダ式、ストリーム、関数型インターフェース~

    2019年11月4日
  • ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    ReactのためのEslintおよびPrettierの設定方法 ~Airbnb JavaScript Style Guideの適用~

    2019年10月30日
  • BashからZshに移行する方法(Mac編)

    BashからZshに移行する方法(Mac編)

    2019年10月21日
  • Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    Create React Appを使わないでゼロからReactの開発環境を構築する方法(Webpack/Docker編)

    2019年9月30日

カテゴリ

  • 技術 Tips & Tutorials (100)
  • 技術塾 (6)
  • ライフハック (26)
  • 海外留学 (12)
  • 英語学習 (3)
  • コラム (6)

アーカイブ

最高の学習のために

人気記事ランキング

  • MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
    MySQLで「ERROR 2003 (HY000): Can't connect to MySQL server」と怒られた時の対処法
  • Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
    Jupyter Notebookで「The kernel appears to have died. It will restart automatically.」というエラーが出た場合の原因と対処法
  • Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
    Expressで「Cannot set headers after they are sent to the client」と怒られた時の対処法
  • 爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
    爆速でJenkinsをマスターしよう(GitHubアカウント統合編) ~ JenkinsのGitHub Organizationの設定方法 ~
  • SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
    SAKURAのメールボックスで独自ドメインのメールを設定し、Gmail経由で送受信する方法
  • バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
    バンクーバー留学豆知識:バンクーバーのATMで日本の銀行のキャッシュカードを使ってお得にお金を引き出す方法
  • [tips][perl] Perlで文字コードをいい感じに処理する方法
    [tips][perl] Perlで文字コードをいい感じに処理する方法
  • PythonでWebスクレイピング入門(Scrapy+Selenium編)
    PythonでWebスクレイピング入門(Scrapy+Selenium編)
  • Amazon EC2インスタンスにSSHできなくなった時の対処法
    Amazon EC2インスタンスにSSHできなくなった時の対処法
  • SpringBootのProfile毎にプロパティを使い分ける3つの方法
    SpringBootのProfile毎にプロパティを使い分ける3つの方法

Bitcoin寄付 / BTC Donation

Bitcoinを寄付しよう

BTC
Select Payment Method
Personal Info

Donation Total: BTC 0.0010

このブログの運営のためにBitcoinでの寄付を募集しています。お気持ち程度の寄付を頂けると管理者の励みになります。

Bitcoin寄付について知りたい方はこちらの記事へ

ビットコイン取引ならここ

  • ホーム
  • 技術 Tips & Tutorials
  • 技術塾
  • ライフハック
  • 海外留学
  • 英語学習
  • コラム
  • サイトマップ
  • タグ一覧
  • プライバシーポリシー
  • お問い合わせ

Copyright © 2023 KD - Casual Developers Notes