Firebase vs Supabase
Google全面的移动开发平台Firebase,对阵开源PostgreSQL替代方案Supabase。在选择后端即服务(BaaS)时该如何取舍?
基于资源、无状态,遵循通用的 HTTP 标准
一种查询语言——客户端精确指定自己想要的数据
| 分类 | REST API | GraphQL |
|---|---|---|
| 性能 | 8/10 | 8/10 |
| 学习难易度 | 9/10 | 6/10 |
| 生态系统 | 10/10 | 8/10 |
| 社区 | 10/10 | 8/10 |
| 就业市场 | 10/10 | 8/10 |
| 面向未来 | 8/10 | 9/10 |
// Swift - REST API 客户端
import Foundation
enum HTTPMethod: String {
case GET, POST, PUT, DELETE, PATCH
}
struct APIClient {
private let baseURL = URL(string: "https://api.example.com")!
private let session: URLSession
init(session: URLSession = .shared) {
self.session = session
}
func request<T: Decodable>(
path: String,
method: HTTPMethod = .GET,
body: Encodable? = nil
) async throws -> T {
var url = baseURL.appendingPathComponent(path)
var request = URLRequest(url: url)
request.httpMethod = method.rawValue
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(AuthManager.shared.token)", forHTTPHeaderField: "Authorization")
if let body {
request.httpBody = try JSONEncoder().encode(body)
}
let (data, response) = try await session.data(for: request)
guard let http = response as? HTTPURLResponse else {
throw APIError.invalidResponse
}
switch http.statusCode {
case 200...299:
return try JSONDecoder().decode(T.self, from: data)
case 401:
throw APIError.unauthorized
case 404:
throw APIError.notFound
default:
throw APIError.serverError(http.statusCode)
}
}
}
// 使用示例
let client = APIClient()
let user: User = try await client.request(path: "/users/123")
let posts: [Post] = try await client.request(path: "/users/123/posts")// Swift - GraphQL Apollo 客户端
import Apollo
import Foundation
// GraphQL 查询定义(由代码生成)
// query GetUserWithPosts($id: ID!) {
// user(id: $id) {
// id
// name
// email
// posts(limit: 5) {
// id
// title
// excerpt
// publishedAt
// }
// }
// }
class GraphQLService {
private lazy var apollo = ApolloClient(url: URL(string: "https://api.example.com/graphql")!)
func fetchUserWithPosts(id: String) async throws -> UserWithPostsQuery.Data.User {
try await withCheckedThrowingContinuation { continuation in
apollo.fetch(query: UserWithPostsQuery(id: id)) { result in
switch result {
case .success(let graphQLResult):
if let errors = graphQLResult.errors {
continuation.resume(throwing: GraphQLError(errors))
} else if let user = graphQLResult.data?.user {
continuation.resume(returning: user)
} else {
continuation.resume(throwing: APIError.notFound)
}
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
func createPost(title: String, content: String) async throws -> CreatePostMutation.Data.CreatePost {
try await withCheckedThrowingContinuation { continuation in
apollo.perform(mutation: CreatePostMutation(title: title, content: content)) { result in
switch result {
case .success(let graphQLResult):
if let post = graphQLResult.data?.createPost {
continuation.resume(returning: post)
} else {
continuation.resume(throwing: APIError.invalidResponse)
}
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
}对于中小型 API 和公开集成,选 REST——简单、通用、缓存友好。如果有复杂的数据需求、多个客户端,并且需要快速的产品迭代,GraphQL 是个有力的选择。2025 年,许多公司采用混合方案:用 REST 承载稳定的吞吐量,用 GraphQL 处理需要灵活性的查询。
获取免费咨询不会。两者服务于不同的使用场景。REST 会继续保持简单和通用;GraphQL 则是应对复杂产品需求的有力替代方案。