RESTful API

f:id:utouto97:20210725220816p:plain

RESTful API

RESTful API (REST API) は、RESTに基づいたAPIのことです。

REST

RESTとは、REpresentational State Transferのことで、ロイ・フィールディング氏によって提唱されました。

RESTには、次のような原則があります。

  • ステートレスなクライアント/サーバプロトコル
    HTTPメッセージの一つ一つが、そのリクエスト(メッセージ)を理解するために必要な全ての情報を含む。そのため、クライアントもサーバも、メッセージ間におけるセッションの状態を記憶しておく必要がない。ただし実際には、多くのHTTPベースのアプリケーションはクッキーやその他の仕掛けを使ってセッションの状態を管理している(URLリライティングのような一部のセッション管理手法を使うシステムは、RESTfulではない)。
  • すべての情報(リソース)に適用できる「よく定義された操作」のセット
    HTTP では操作(メソッド)の小さなセットが定義されている。最も重要なのは "GET"、"POST"、"PUT"、"DELETE" である。これらはデータ永続化に要求されるCRUDと比較されることがある。もっとも "POST" に関してはCRUDにはぴったり対応していない。
  • リソースを一意に識別する「汎用的な構文」
    RESTfulなシステムでは、すべてのリソースはUniform Resource Identifier (URI) で表される一意的な(ユニークな)アドレスを持つ。
  • アプリケーションの情報と状態遷移の両方を扱うことができる「ハイパーメディアの使用」
    RESTシステムでは、多くの場合、HTML文書またはXML文書を使う。こうした文書に情報およびその他のリソースへのリンクを含める。こうすることにより、あるRESTリソースから他のRESTリソースを参照したい場合は単にリンクを辿るだけでよい。レジストリなどの他の基盤的な機能を使う必要はない。

Representational State Transfer - Wikipedia

REST APIの特徴

URIでリソースを指定

REST APIでは、URI (エンドポイント)でリソースを指定します。
例えば、ユーザー(User)に対して操作をする場合はhttp://example.com/api/user、 投稿(Post)に対して操作する場合はhttp://example.com/api/postのようになります。

HTTPメソッドで処理を指定

先に述べたように、REST APIではURIでリソースを指定します。
そして、そのリソースに対してどのような処理を行うかをHTTPメソッドで指定します。

HTTPメソッドには、GET, POST, PUT, PATCH, DELETEなどがあります。
これらはそれぞれ、取得、作成、更新、更新、削除、として一般的に使われます。

REST APIの例

  1. ユーザー一覧の取得

エンドポイント http://example.com/api/user
HTTPメソッド GET

  1. ユーザーの新規追加

エンドポイント http://example.com/api/user
HTTPメソッド POST

  1. ユーザー情報の更新

エンドポイント http://example.com/api/user
HTTPメソッド PATCH

  1. ユーザーの削除

エンドポイント http://example.com/api/user
HTTPメソッド DELETE

α. 投稿に関する処理

上で示したユーザーの例で、エンドポイントをhttp://example.com/api/postに変更する。

REST APIは、このような感じのAPIになります。

終わり

DockerでMongoDB永続化

f:id:utouto97:20210704222355j:plain

DockerでMongoDB永続化

DockerでMongoDBサーバーを立てていて、そのデータを永続化する方法をまとめていきます。
Dockerは、docker-composeを使って設定していきます。

DockerでMongoDBを永続化するには、ボリュームの設定をして、/data/dbにマウントするだけです。 今回はdocker-composeを使って設定するので、volumesに設定を書きます。

version: '3'
services:
  db:
    image: mongo
    volumes:
      - db_data:/data/db

volumes:
  db_data:

これで、設定は完了です。
あとは、docker-compose upすると、そのMongoDBのデータは永続化されました。

終わり

RailsでMongoDBを使う

f:id:utouto97:20210704222353j:plain

Mongoid

RailsでMongoDBを使うには、Mongoidを利用します。

Mongoidは、RubyのMongoDB用ORMです。
RailsRDBを利用する場合、Active Recordが広く使われていますが、それのMongoDB版だということです。

Mongoidは、Active Recordと似たようなインターフェースがあり、Active Recordを使ったことがある人は使いやすいと思います。

実際に試してみる

Mongoidのインストール

では、実際にMongoidを使っていきます。

まず、Railsプロジェクトの作成時に、--skip-active-recordオプションをつけることで、Active Recordをスキップします。
それと同時に、通常のRDB関連のGemもインストールしません。

$ rails new . --skip-active-record --force

MongoidはGemでインストールできるので、Gemfileに追記して、bundle installします。

gem 'mongoid'

bundle installすると、Mongoidのインストールは完了です。

RailsでMongoidを使う

rails g scaffoldで一気にいろいろ生成します。

$ docker-compose run rails rails g scaffold user name age:integer --timestamp

これで、Userモデルやそのコントローラが作成されました。
ルーティングも自動で設定されています。

f:id:utouto97:20210818210846p:plain

http://localhost:3000/usersにアクセスすると、↑のようなページが表示されました。
(ユーザー追加してます)

Mongoidのモデルの使用例

先に説明した方法で生成されたモデルの使用例をいくつかみてみます。
(それぞれ抜粋です)

# 新規作成
@user = User.new(user_params)

# 更新
@user.update(user_params)

# 消去
@user.destroy

# 検索
@user = User.find(params[:id])

見てわかる通り、ActiveRecordとほぼ同様の方法で操作できます。
ただし、MongoDBでは結合ができないため、Mongoidのモデルでも結合ができません。
その他にも、いくつかActive Recordと異なる点があります。

終わり

MongoDBに認証を設定する

f:id:utouto97:20210704222355j:plain

MongoDBに認証を設定する

MongoDBはデフォルトでは認証が設定されていません。
つまり、MongoDBに接続できれば、誰でもDBを操作することができてしまいます。
このままでは、セキュリティ的に大問題なので、ユーザー認証を設定し、ログインしないとDB操作できないようにします。

管理ユーザーを作成する

まず、はじめに、データベース全体を管理する管理ユーザーを作成します。
管理ユーザーはadminデータベースに作成します。
ユーザーの作成はcreateUser()です。

use admin
db.createUser({
 user: "admin",
 pwd: "password",
 roles: [
  {
   role: "userAdminAnyDatabase",
   db: "admin"
  },
 ]
})

やっていることは、use adminでadminデータベースを選択し、createUser()でユーザーを作成しているだけです。
権限として、userAdminAnyDatabaseを指定することで、 各データベースの管理ユーザーとしています。

管理ユーザーでログイン

db.auth("ユーザー名", "パスワード")でログインすることができます。

db.auth("admin", "password")

ログインに成功すれば1が返ってきます。
ログイン失敗時は0です。

一般ユーザーを作成

では、一般のデータベースを選択し、そのデータベースのユーザーを作成していきます。
ここでは、testというデータベースに一般ユーザーを作成しています。

use test
db.createUser({
 user: "user1",
 pwd: "password",
 roles: [
  {
   role: "readWrite",
   db: "test"
  },
 ]
})

認証をONにしてMongoDBを起動

ユーザーを作成できたので、MongoDBのアクセスに認証を必要とします。
サーバーの起動時に、--authオプションを付けることで、認証が必要になります。

$ mongod --auth

mongoコマンドでログインする

mongoコマンドでアクセスする場合、-uオプションでユーザー名、-pオプションでパスワードを設定することでログインすることができます。
このとき、--authenticationDatabaseでデータベースを指定します。

$ mongo -u "user1" -p "password" --authenticationDatabase "test"

終わり

MongoDBでインデックス

f:id:utouto97:20210725220657j:plain

MongoDBでインデックスを作成する

インデックスを確認

この時点でのインデックスを確認してみます。
インデックスの確認には、getIndexes()を使います。

> db.User.getIndexes()
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]

_idが1になっています。
これは、_id属性に対して昇順でインデックスが張られていることを示しています。

インデックスを作成

では、インデックスを作成していきます。
インデックスの作成は、createIndexで行います。

> db.User.createIndex({ name: 1 })
{
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}

name: 1を引数として渡しています。
これは、name属性を昇順でインデックス作成することを示しています。

インデックスが作成できたので、再度インデックスを確認してみます。

> db.User.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1
                },
                "name" : "name_1"
        }
]

nameの昇順インデックスが追加されていることが確認できました。

createIndexの引数には、複数のキーを渡すことができ、その場合は複合インデックスとなります。

終わり

MongoDBを触ってみる

f:id:utouto97:20210706233740j:plain

MongoDBを触る準備

今回は、Docker-Composeを使ってMongoDBをセットアップしました。

docker-compose.ymlの中身は↓です。

version: '3'

services:
  mongo:
    image: mongo

あとは、docker-compose upしたら、MongoDBのサーバーが立ちました。
docker-compose exec mongo bashで中に入り操作していきます。

MongoDBを触ってみる

MongoDBをインストールできたら、mongoコマンドでMongoDBを操作することができます。

$ mongo

DB作成・選択

use DB名;とするだけです。
DBの選択だけでなく、作成も自動で行われます。

> use Sample;
switched to db Sample

これでSampleというデータベースを作成できました。
show dbs;でDB一覧を確認することができます。

コレクションの作成

RDBのテーブルにあたるところのコレクションを作っていきます。
コレクションを作成するには、createCollection()を使います。

> db.createCollection('User');
{ "ok" : 1 }

コレクションを作成できました。
show collections;でコレクションの一覧を確認できます。

データの追加

insert()を使って、データを追加します。
JSON形式で渡せば、すきな属性を付与することができます。

> db.User.insert({name: 'Ken', age: 10})
WriteResult({ "nInserted" : 1 })
> db.User.insert({name: 'Mari', gender: 'f'})
WriteResult({ "nInserted" : 1 })

データの一覧を取得

データの一覧を取得して、データが追加されていることを確認します。
データの取得には、find()を使う

> db.User.find()
{ "_id" : ObjectId("611681fa60f9dd4792a46c02"), "name" : "Ken", "age" : 10 }
{ "_id" : ObjectId("6116821a60f9dd4792a46c03"), "name" : "Mari", "gender" : "f" }

find()の第一引数には、条件を指定することができます。

> db.User.find({ gender: 'f' })
{ "_id" : ObjectId("6116821a60f9dd4792a46c03"), "name" : "Mari", "gender" : "f" }

また、演算子も利用できます。

> db.User.find({ age: { $lt: 15 }})
{ "_id" : ObjectId("611681fa60f9dd4792a46c02"), "name" : "Ken", "age" : 10 }

find()の第二引数で取得したい属性を指定できます。

> db.User.find({}, { name:1, _id:0 })
{ "name" : "Ken" }
{ "name" : "Mari" }

データの更新

データの更新はupdate()でできます。
第一引数が条件、第二引数が更新内容です。

> db.User.update({name: 'Ken'}, {age: 15})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.User.find()
{ "_id" : ObjectId("611681fa60f9dd4792a46c02"), "age" : 15 }
{ "_id" : ObjectId("6116821a60f9dd4792a46c03"), "name" : "Mari", "gender" : "f" }

今回はここまで!

終わり

MongoDB

f:id:utouto97:20210704221944p:plain

MongoDB

MongoDBは、ドキュメント型のNoSQLデータベースです。
C++で開発されていて、人気のあるデータベースの一つです。

「MongoDBでは、どのようにデータを保存・管理しているの?」

MongoDBはドキュメント型のNoSQLです。

MongoDBでは、JSONのような「ドキュメント」という形式でデータを格納します。
RDBのテーブルとは異なりスキーマがないため、柔軟なデータを格納することができます。
そして、「ドキュメント」を集めたものが「コレクション」です。
複数のドキュメントを束ねて、一つのコレクションとして扱います。

「MongoDBの強みと弱みは?」

MongoDBは、次のような強みがあります。

  • JSON形式で階層型データを扱える
    MongoDBはJSON形式でデータを格納するため、階層型のデータを格納できます。
    また、きちっと決められたスキーマがあるわけではないため、柔軟なデータを扱うことができます。
  • 強力なインデックス
    セカンダリインデックスや複合キーインデックス、マルチキーインデックスといった便利なインデックスがあります。
  • SQLに似せたクエリで扱いやすい
    NoSQLであるMongoDBですが、SQLに似たクエリで、扱いやすいです。
  • 水平分割・複製が容易
    ドキュメント型のNoSQLであるMongoDBは、水平分割や複製が容易にできます。

一方で、MongoDBには次のような弱みもあります。

  • トランザクションがなく、一貫性を保証できない
    MongoDBでは、複数のドキュメントを一貫性を保って更新することはできません。
    そのため、複数ドキュメントで一貫性を保証する必要がある場合、利用できません。
  • 結合ができない
    MongoDBでは、ドキュメントの結合をすることができません。
    そのため、複数ドキュメントの内容を統合して処理する場合、アプリケーション側で実装する必要があります。
  • スキーマがないため、データ型が不定 MongoDBはスキーマがありません。
    そのことは、柔軟に様々な形式のデータを扱えるといったメリットがある一方で、デメリットもあります。
    スキーマがなく、キー名やデータ型が不明です。
    そのため、保守性の低下といった問題があります。
    これは動的型付け言語と似たようなイメージです。

終わり