REST API vs GraphQL
20年以上の歴史を持つRESTと、Facebook発のGraphQLを比較。モバイルアプリのバックエンドには、どちらのAPI設計パラダイムを選ぶべきか?
Googleの包括的なモバイルアプリ開発プラットフォーム
オープンソースのFirebase代替 — PostgreSQLベース、セルフホスト可能
| カテゴリー | Firebase | Supabase |
|---|---|---|
| パフォーマンス | 9/10 | 9/10 |
| 学習のしやすさ | 8/10 | 7/10 |
| エコシステム | 10/10 | 7/10 |
| コミュニティ | 9/10 | 8/10 |
| 求人市場 | 9/10 | 7/10 |
| 将来性 | 7/10 | 9/10 |
// Firebase - リアルタイムチャットメッセージ
import FirebaseFirestore
import FirebaseAuth
import SwiftUI
@Observable
class ChatViewModel {
var messages: [Message] = []
private var listener: ListenerRegistration?
private let db = Firestore.firestore()
struct Message: Identifiable, Codable {
@DocumentID var id: String?
let senderId: String
let senderName: String
let text: String
let timestamp: Timestamp
}
func startListening(roomId: String) {
listener = db.collection("rooms")
.document(roomId)
.collection("messages")
.order(by: "timestamp", descending: false)
.limit(toLast: 50)
.addSnapshotListener { [weak self] snapshot, error in
guard let documents = snapshot?.documents else { return }
self?.messages = documents.compactMap {
try? $0.data(as: Message.self)
}
}
}
func sendMessage(text: String, roomId: String) async throws {
guard let user = Auth.auth().currentUser else { return }
let message = Message(
senderId: user.uid,
senderName: user.displayName ?? "Anonim",
text: text,
timestamp: Timestamp()
)
try db.collection("rooms")
.document(roomId)
.collection("messages")
.addDocument(from: message)
}
func stopListening() { listener?.remove() }
}// Supabase - ユーザー投稿CRUD
import Supabase
import Foundation
struct Post: Codable, Identifiable {
let id: UUID
let userId: UUID
let title: String
let content: String
let createdAt: Date
enum CodingKeys: String, CodingKey {
case id, title, content
case userId = "user_id"
case createdAt = "created_at"
}
}
class PostRepository {
private let client = SupabaseClient(
supabaseURL: URL(string: ProcessInfo.processInfo.environment["SUPABASE_URL"]!)!,
supabaseKey: ProcessInfo.processInfo.environment["SUPABASE_ANON_KEY"]!
)
func fetchPosts() async throws -> [Post] {
try await client
.from("posts")
.select("*")
.order("created_at", ascending: false)
.limit(20)
.execute()
.value
}
func createPost(title: String, content: String) async throws -> Post {
let userId = try await client.auth.session.user.id
return try await client
.from("posts")
.insert(["user_id": userId.uuidString, "title": title, "content": content])
.select()
.single()
.execute()
.value
}
func subscribeToNewPosts(onNewPost: @escaping (Post) -> Void) -> RealtimeChannelV2 {
let channel = client.channel("public:posts")
channel.onPostgresChange(
InsertAction.self,
table: "posts"
) { change in
if let post = try? change.record.decode(as: Post.self) {
onNewPost(post)
}
}
Task { await channel.subscribe() }
return channel
}
}迅速な開発、優れたiOS SDK、リアルタイム機能を求めるならFirebaseが強力です。リレーショナルデータ、SQLの柔軟性、オープンソース、ベンダーロックインへの懸念があるならSupabaseを選びましょう。2025年、Supabaseは急速に成熟しており、真剣な競合となっています — 特にAI機能搭載アプリ向けのpgvector統合が注目されています。
無料相談を受ける可能ですが容易ではありません。FirestoreのNoSQL構造をPostgreSQLスキーマに変換し、Authユーザーを移行し、Storageのファイルを転送する必要があります。大規模な移行プロジェクトが必要です。