Firebase vs Supabase
La completa plataforma móvil de Google, Firebase, se enfrenta a Supabase, la alternativa de código abierto basada en PostgreSQL. ¿Qué elegir al seleccionar un Backend-as-a-Service?
Basado en recursos, sin estado, estándares HTTP universales
Lenguaje de consulta — el cliente especifica exactamente lo que necesita
| Categoría | REST API | GraphQL |
|---|---|---|
| Rendimiento | 8/10 | 8/10 |
| Facilidad de aprendizaje | 9/10 | 6/10 |
| Ecosistema | 10/10 | 8/10 |
| Comunidad | 10/10 | 8/10 |
| Mercado laboral | 10/10 | 8/10 |
| A prueba de futuro | 8/10 | 9/10 |
// Swift - cliente de API REST
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)
}
}
}
// Uso
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 - cliente Apollo GraphQL
import Apollo
import Foundation
// Definición de consulta GraphQL (generada desde el código)
// 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)
}
}
}
}
}Para APIs pequeñas-medianas e integraciones públicas, REST — simple, universal, amigable con el caché. Si hay requisitos de datos complejos, múltiples clientes e iteración rápida de producto, GraphQL es una opción potente. En 2025 muchas empresas adoptan un enfoque híbrido: REST para rendimientos seguros, GraphQL para consultas que requieren flexibilidad.
Solicita una consultoría gratuitaNo. Ambos sirven a casos de uso diferentes. REST seguirá siendo simple y universal; GraphQL es una alternativa potente para necesidades de producto complejas.