1500+ lines of backend integration mastery - REST APIs, GraphQL, WebSockets, authentication, Firebase, error handling with production-ready code examples.
Provides production-ready patterns for Flutter backend integration including REST APIs, GraphQL, WebSockets, authentication, and Firebase. Use when building data layers, API clients, or handling network requests with proper error handling and retry logic.
/plugin marketplace add pluginagentmarketplace/custom-plugin-flutter/plugin install custom-plugin-flutter@pluginagentmarketplace-flutterThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/backend_config.yamlreferences/BACKEND_GUIDE.mdscripts/api_helper.pyfinal dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
));
// Add logging interceptor
dio.interceptors.add(LoggingInterceptor());
// Make request
Future<User> getUser(String id) async {
try {
final response = await dio.get('/users/$id');
return User.fromJson(response.data);
} on DioException catch (e) {
throw ApiException(e.message ?? 'Unknown error');
}
}
HTTP Package (Lightweight):
import 'package:http/http.dart' as http;
Future<User> getUser(String id) async {
final response = await http.get(
Uri.parse('https://api.example.com/users/$id'),
headers: {'Authorization': 'Bearer $token'},
);
if (response.statusCode == 200) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load user');
}
}
Dio Framework (Production):
final dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
));
// Add interceptors
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) async {
options.headers['Authorization'] = 'Bearer $token';
return handler.next(options);
},
onError: (error, handler) async {
if (error.response?.statusCode == 401) {
await _refreshToken();
}
return handler.next(error);
},
),
);
// Use Dio
final response = await dio.get('/users/123');
Repository Pattern:
abstract class UserRepository {
Future<User> getUser(String id);
Future<List<User>> getAllUsers();
Future<void> createUser(User user);
}
class UserRepositoryImpl implements UserRepository {
final Dio _dio;
UserRepositoryImpl(this._dio);
@override
Future<User> getUser(String id) async {
try {
final response = await _dio.get('/users/$id');
return User.fromJson(response.data);
} on DioException catch (e) {
throw _handleError(e);
}
}
@override
Future<List<User>> getAllUsers() async {
try {
final response = await _dio.get('/users');
return (response.data as List)
.map((u) => User.fromJson(u))
.toList();
} on DioException catch (e) {
throw _handleError(e);
}
}
Exception _handleError(DioException e) {
if (e.type == DioExceptionType.connectionTimeout) {
return TimeoutException('Connection timeout');
} else if (e.response?.statusCode == 401) {
return UnauthorizedException('Unauthorized');
} else if (e.response?.statusCode == 500) {
return ServerException('Server error');
}
return ApiException('Unknown error');
}
}
import 'package:graphql/client.dart';
final graphQLClient = GraphQLClient(
cache: GraphQLCache(),
link: HttpLink('https://api.example.com/graphql'),
);
// Query
Future<User> getUser(String id) async {
final result = await graphQLClient.query(
QueryOptions(
document: gql('''
query GetUser(\$id: ID!) {
user(id: \$id) {
id
name
email
}
}
'''),
variables: {'id': id},
),
);
if (result.hasException) {
throw Exception(result.exception);
}
return User.fromJson(result.data!['user']);
}
// Mutation
Future<void> updateUser(User user) async {
final result = await graphQLClient.mutate(
MutationOptions(
document: gql('''
mutation UpdateUser(\$id: ID!, \$name: String!) {
updateUser(id: \$id, name: \$name) {
id
name
}
}
'''),
variables: {'id': user.id, 'name': user.name},
),
);
if (result.hasException) {
throw Exception(result.exception);
}
}
JWT Token Management:
class AuthService {
final Dio _dio;
String? _accessToken;
String? _refreshToken;
AuthService(this._dio);
Future<void> login(String email, String password) async {
try {
final response = await _dio.post('/auth/login', data: {
'email': email,
'password': password,
});
_accessToken = response.data['accessToken'];
_refreshToken = response.data['refreshToken'];
await _secureStorage.write(
key: 'accessToken',
value: _accessToken!,
);
await _secureStorage.write(
key: 'refreshToken',
value: _refreshToken!,
);
} on DioException catch (e) {
throw _handleError(e);
}
}
Future<String> getValidToken() async {
if (_isTokenExpired(_accessToken)) {
await _refreshAccessToken();
}
return _accessToken!;
}
Future<void> _refreshAccessToken() async {
try {
final response = await _dio.post(
'/auth/refresh',
data: {'refreshToken': _refreshToken},
);
_accessToken = response.data['accessToken'];
await _secureStorage.write(
key: 'accessToken',
value: _accessToken!,
);
} catch (e) {
await logout();
rethrow;
}
}
bool _isTokenExpired(String? token) {
if (token == null) return true;
final decoded = jwt.decode(token);
final expiration = DateTime.fromMillisecondsSinceEpoch(
decoded['exp'] * 1000,
);
return DateTime.now().isAfter(expiration);
}
Future<void> logout() async {
_accessToken = null;
_refreshToken = null;
await _secureStorage.deleteAll();
}
}
Custom Exceptions:
abstract class ApiException implements Exception {
final String message;
ApiException(this.message);
}
class NetworkException extends ApiException {
NetworkException(String message) : super('Network Error: $message');
}
class UnauthorizedException extends ApiException {
UnauthorizedException(String message) : super('Unauthorized: $message');
}
class ServerException extends ApiException {
ServerException(String message) : super('Server Error: $message');
}
class ValidationException extends ApiException {
final Map<String, String> errors;
ValidationException(this.errors) : super('Validation Error');
}
import 'package:cloud_firestore/cloud_firestore.dart';
class FirebaseUserRepository {
final firestore = FirebaseFirestore.instance;
Future<User?> getUser(String id) async {
try {
final doc = await firestore.collection('users').doc(id).get();
if (!doc.exists) return null;
return User.fromJson(doc.data()!);
} catch (e) {
throw Exception('Failed to get user: $e');
}
}
Stream<User?> watchUser(String id) {
return firestore
.collection('users')
.doc(id)
.snapshots()
.map((doc) => doc.exists ? User.fromJson(doc.data()!) : null);
}
Future<void> updateUser(User user) async {
await firestore.collection('users').doc(user.id).update(
user.toJson(),
);
}
Future<void> createUser(User user) async {
await firestore.collection('users').doc(user.id).set(
user.toJson(),
);
}
}
Future<T> withRetry<T>(
Future<T> Function() operation, {
int maxRetries = 3,
Duration initialDelay = const Duration(milliseconds: 100),
}) async {
int retries = 0;
Duration delay = initialDelay;
while (true) {
try {
return await operation();
} catch (e) {
if (retries >= maxRetries || !_isRetryable(e)) {
rethrow;
}
await Future.delayed(delay);
delay = Duration(milliseconds: (delay.inMilliseconds * 2).toInt());
retries++;
}
}
}
bool _isRetryable(dynamic error) {
if (error is! DioException) return false;
return error.type == DioExceptionType.connectionTimeout ||
error.type == DioExceptionType.receiveTimeout ||
(error.response?.statusCode ?? 0) >= 500;
}
Master backend integration for robust Flutter applications.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.