SDK Dart ainda não disponível. Enquanto isso, use a REST API diretamente — é simples e funciona hoje.
Precisa do SDK Dart? Conte pelo suporte →
Usando a REST API diretamente
O SuperDB expõe APIs REST padrão. Com o pacote http do Dart, você pode fazer signup, login e queries de banco de dados sem nenhum SDK específico.
Uma diferença que vale ler antes de escrever código: o login devolve dois tokens. O access_token é a sessão; o data_plane_token é o único que api.superdb.com.br aceita. O SDK esconde isso — chamando por HTTP, você escolhe.
Dependências necessárias
Adicione ao pubspec.yaml:
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
flutter_secure_storage: ^9.0.0 # armazenar JWT de forma segura
shared_preferences: ^2.2.0 # alternativa simples
Signup e login
A API de auth do SuperDB segue o padrão GoTrue. Os endpoints são:
- Signup:
POST /auth/v1/signup - Login:
POST /auth/v1/signin
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class AuthService {
static const String baseUrl = 'https://auth.superdb.com.br';
static const String anonKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
// O slug do seu projeto. É ELE que diz ao servidor de qual tenant se trata —
// a anon key não faz isso. Sem este header, toda chamada de auth devolve
// 404 tenant_not_found, que é fácil confundir com URL errada.
static const String projeto = 'meu-projeto';
final _storage = const FlutterSecureStorage();
Map<String, String> get _headers => {
'Content-Type': 'application/json',
'X-SuperDB-Project': projeto,
'apikey': anonKey,
};
Future<Map<String, dynamic>?> signUp(String email, String password) async {
final response = await http.post(
Uri.parse('$baseUrl/auth/v1/signup'),
headers: _headers,
body: jsonEncode({'email': email, 'password': password}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// São DOIS tokens. O access_token é a sessão (auth.superdb.com.br);
// o data_plane_token é o único que api.superdb.com.br aceita.
await _storage.write(key: 'access_token', value: data['access_token']);
await _storage.write(key: 'data_plane_token', value: data['data_plane_token']);
await _storage.write(key: 'refresh_token', value: data['refresh_token']);
return data;
}
throw Exception('Signup falhou: ${response.body}');
}
Future<Map<String, dynamic>?> signIn(String email, String password) async {
final response = await http.post(
Uri.parse('$baseUrl/auth/v1/signin'),
headers: _headers,
body: jsonEncode({'email': email, 'password': password}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
// São DOIS tokens. O access_token é a sessão (auth.superdb.com.br);
// o data_plane_token é o único que api.superdb.com.br aceita.
await _storage.write(key: 'access_token', value: data['access_token']);
await _storage.write(key: 'data_plane_token', value: data['data_plane_token']);
await _storage.write(key: 'refresh_token', value: data['refresh_token']);
return data;
}
throw Exception('Login falhou: ${response.body}');
}
/// Sessão — use em auth.superdb.com.br (logout, trocar senha, etc).
Future<String?> getToken() async {
return await _storage.read(key: 'access_token');
}
/// Dados — é ESTE que vai no Authorization de api.superdb.com.br.
/// Vale 1 hora; renove em /auth/v1/token/refresh com o refresh_token.
Future<String?> getDataPlaneToken() async {
return await _storage.read(key: 'data_plane_token');
}
Future<void> signOut() async {
final token = await getToken();
if (token != null) {
await http.post(
Uri.parse('$baseUrl/auth/v1/signout'),
headers: { ..._headers, 'Authorization': 'Bearer $token' },
);
}
await _storage.deleteAll();
}
}
Queries no banco de dados
O banco de dados é acessível via PostgREST. Use o JWT do usuário no header Authorization — o RLS filtra automaticamente os dados conforme as policies configuradas.
import 'dart:convert';
import 'package:http/http.dart' as http;
class DatabaseService {
// Dados: api.superdb.com.br (NÃO auth.superdb.com.br)
// Path: raiz da tabela, sem prefixo /rest/v1/
static const String dataUrl = 'https://api.superdb.com.br';
// Passe SEMPRE o data_plane_token (auth.getDataPlaneToken()).
// Mandar o access_token aqui devolve 401.
Future<List<dynamic>> fetchPosts(String dataPlaneToken) async {
// Correto: api.superdb.com.br/posts (sem /rest/v1/)
// O tenant sai do próprio token — não precisa de Accept-Profile.
final response = await http.get(
Uri.parse('$dataUrl/posts?order=created_at.desc&limit=20'),
headers: {
'Authorization': 'Bearer $dataPlaneToken',
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
return jsonDecode(response.body) as List<dynamic>;
}
throw Exception('Query falhou: ${response.statusCode}');
}
Future<void> insertPost(String dataPlaneToken, String title, String body) async {
final response = await http.post(
Uri.parse('$dataUrl/posts'),
headers: {
'Authorization': 'Bearer $dataPlaneToken',
'Content-Type': 'application/json',
'Prefer': 'return=minimal',
},
body: jsonEncode({'title': title, 'body': body}),
);
if (response.statusCode != 201) {
throw Exception('Insert falhou: ${response.body}');
}
}
}
Quando o SDK Dart estiver disponível
O SDK nativo simplificará esse código consideravelmente — sem headers manuais, com tipagem Dart completa e refresh automático de tokens. Enquanto ele não sai:
- Peça o SDK Dart pelo suporte
- Referência completa da API REST
- Como funcionam os JWT tokens
- Expo (React Native) — SDK JS disponível hoje