こんにちは。

昔から好きだった「笑ゥせぇるすまん」のガチャを、最近中野で発見しご機嫌なバックエンド担当の鈴木です。

本記事ではREST、RPC、GraphQLについて書きたいと思います。

REST、RPC、GraphQLの基本的な違い

REST(Representational State Transfer)

リソース指向であり、HTTPメソッドを用いてリソースのCRUD操作を表現します。

各リクエストは独立しています。

RPC(Remote Procedure Call)

遠隔手続き呼出しを意味し、クライアントがサーバー上のメソッドや関数を直接呼び出すことができます。

JSON-RPCやXML-RPCなどがあります。

GraphQL

クライアントが必要なデータの構造を指定し、一回のリクエストで多様なデータを取得できるクエリ言語です。

バックエンドとフロントエンド間のデータ取得を最適化します。

REST、RPC、GraphQLの歴史と特徴

REST

歴史

  • RESTは2000年にRoy Fieldingによって最初に作られた用語です。
  • インターネットの基盤技術であるHTTPプロトコルを利用して、ウェブサービス間のやり取りを簡素化することを目的としています。

特徴

  • RESTはステートレスなアーキテクチャを採用しており、各リクエストが独立して完結している必要があります。
  • リソース指向であり、URIでリソースを指定し、HTTPメソッド(GET、POST、PUT、DELETE)を用いてリソースに対する操作を定義します。
  • シンプルさと拡張性に重点を置いています。

RPC

歴史

  • RPCは1970年代後半から1980年代初頭にかけて開発されました。

特徴

  • RPCはスレートレス、ステートフルどちらも利用する可能です。
  • クライアントがサーバー上のプロシージャをローカルで実行しているかのように呼び出すことができるため、直感的なメソッド呼び出しによるAPI設計が可能です。
  • HTTPメソッドとは独立した、より手続き的なアプローチを取ります。

GraphQL

歴史

  • GraphQLは2015年にFacebookによって開発され、オープンソース化されました。
  • フロントエンドとバックエンド間のデータ取得を効率化することを目的としています。

特徴

  • 高い柔軟性と効率的なデータフェッチが特徴で、クライアントが必要なデータのみを指定できる点が特徴です。 これにより、特にオーバーフェッチやアンダーフェッチを防ぐことが容易に可能なことが特徴です。
  • 複数のリソースから必要なデータを単一のリクエストで取得できるように設計されています。
  • GraphQLは通常、単一のエンドポイントを介してアクセスします。これにより、APIのバージョン管理やエンドポイントの増加に伴う複雑さを減少させることができます。また、APIの構造が単純化されるため、開発と保守が容易になります。

REST、RPC、GraphQLのCRUD操作

REST

# POST /items
def create
@item = Item.new(item_params)
if @item.save
render json: @item, status: :created
else
render json: @item.errors, status: :unprocessable_entity
end
end

# GET /items/:id
def show
render json: @item
end

# PUT /items/:id
def update
if @item.update(item_params)
render json: @item
else
render json: @item.errors, status: :unprocessable_entity
end
end

# DELETE /items/:id
def destroy
@item.destroy
head :no_content
end

RPC

// create
createItem: procedure
.input(z.object({ name: z.string(), description: z.string() }))
.mutation(async ({ input, db }) => {
const item = await db.item.create({ data: input })
return item
}),
// プロシージャを実行するように呼び出せる
const newItem = await trpc.createItem.mutate({ name: "Item Name", description: "Item Description" })

// read
export const appRouter = createRouter()
.query("getItems", {
async resolve({ db }) {
return await db.item.findMany()
},
});
// プロシージャを実行するように呼び出せる
const items = trpc.useQuery(["getItems"]);

// update
updateItem: procedure
.input(z.object({ id: z.string(), name: z.string(), description: z.string() }))
.mutation(async ({ input, db }) => {
const item = await db.item.update({ where: { id: input.id }, data: input })
return item;
}),
// プロシージャを実行するように呼び出せる
const { mutate: updateItem } = trpc.useMutation(["updateItem"])
updateItem({ id: "1", name: "Item Name", description: "Item Description" })

// delete
deleteItem: procedure
.input(z.object({ id: z.string() }))
.mutation(async ({ input, db }) => {
await db.item.delete({ where: { id: input.id } })
return { success: true }
}),

// プロシージャを実行するように呼び出せる
const { mutate: deleteItem } = trpc.useMutation(["deleteItem"])
deleteItem({ id: "削除したいアイテムのID" })

GraphQL

// create
mutation CreateItem($name: String!, $description: String!) {
createItem(name: $name, description: $description) {
id
name
description
}
}

// read
// クライアント側で必要なもののみを指定することが出来る。
query GetItem($id: ID!) {
item(id: $id) {
id
name
description
}
}

// update
mutation UpdateItem($id: ID!, $name: String, $description: String) {
updateItem(id: $id, name: $name, description: $description) {
id
name
description
}
}

// delete
mutation DeleteItem($id: ID!) {
deleteItem(id: $id) {
id
}
}

最後に

実際に使ってみた個人的な感想をまとめて終わります。


<REST>

現在、弊社のサービスでもRESTを利用しています。

印象としては、RESTは使っているサービスが多く、記事も多いためとっつきやすい印象です。

RESTを選択する場面としては、BtoB,BtoCのサービスで選択することが多いと思います。

拡張のしやすさ、他人が作成したコードの理解のしやすさの点で優れていると感じ、 記事も多いため新しく参画した人目線でのとっつきやすさもあると思います。


<RPC>

過去にtRPCとBlitz.jsでRPCを使っていました。

印象としては、開発スピードの効率が高いという印象を持っています。

tRPCはスキーマレスなのにリアルタイムでAPIの型安全を担保してくれる点やBlitz.jsはRuby on Railsのようにセットアップするだけであらゆる機能が搭載済みとなりフロントエンドに集中できる点など、開発スピードは高い方だと思います。

RPCを選択する場面としては、個人プロダクトや社内向けサービスで選択すると思います。

また、BtoB,BtoCのサービスでも、とにかく手っ取り早く作成したい場合などには選択することもあると思います。


<GraphQL>

過去にpythonのFastAPIでGraphQLを使っていました。

印象としては、複数のリソースから必要なデータを単一のリクエストで取得できる点や、柔軟性、オーバーフェッチやアンダーフェッチを防ぎやすい点が開発をするうえでかなりポジティブに働く印象を持っています。

GraphQLを選択する場面としては、単一のエンドポイントでほしいものだけをフェッチすることが出来るため、dbへのアクセス周りを効率的に進めたい場合のシステムに向いていると思います。

注意点として、N+1問題がわかりにくいことが多々あり、問題が発生した際の原因箇所の特定や問題を未然に防ぐようコーディングすることに慣れるまで少し時間がかかるかもしれません。 しかしその反面、正規化が出来ていなかったテーブルに気付ける機会でもありました。

以上になります。最後まで読んでいただきありがとうございました!

参考

https://aws.amazon.com/jp/compare/the-difference-between-rpc-and-rest/

https://xtech.nikkei.com/atcl/learning/lecture/19/00102/00182/

https://trpc.io/

https://blitzjs.com/