API and Integrations - utourismboard/explore-uganda-application-documentation GitHub Wiki
This document details the APIs and third-party integrations used in the Explore Uganda App, including authentication, endpoints, and implementation guidelines.
Production: https://api.exploreuganda.app/v1
Staging: https://staging-api.exploreuganda.app/v1
Development: https://dev-api.exploreuganda.app/v1
// Example Authentication Header
final headers = {
'Authorization': 'Bearer ${userToken}',
'Content-Type': 'application/json',
'Accept': 'application/json',
'Api-Version': 'v1'
};
// User Endpoints
class UserEndpoints {
static const String base = '/users';
static const String profile = '$base/profile';
static const String preferences = '$base/preferences';
static const String notifications = '$base/notifications';
}
// Example User API Call
Future<User> getUserProfile() async {
final response = await dio.get(
UserEndpoints.profile,
options: Options(headers: headers),
);
return User.fromJson(response.data);
}
// Content Endpoints
class ContentEndpoints {
static const String attractions = '/attractions';
static const String events = '/events';
static const String services = '/services';
static const String investments = '/investments';
}
// Example Content API Call
Future<List<Attraction>> getAttractions({
required int page,
required int limit,
String? category,
String? location,
}) async {
final response = await dio.get(
ContentEndpoints.attractions,
queryParameters: {
'page': page,
'limit': limit,
if (category != null) 'category': category,
if (location != null) 'location': location,
},
);
return (response.data['data'] as List)
.map((json) => Attraction.fromJson(json))
.toList();
}
// Google Maps Configuration
class MapsConfig {
static const String apiKey = 'YOUR_GOOGLE_MAPS_API_KEY';
static const String baseUrl = 'https://maps.googleapis.com/maps/api';
static const Map<String, String> endpoints = {
'geocoding': '/geocode/json',
'directions': '/directions/json',
'places': '/place/nearbysearch/json',
};
}
// Example Maps Integration
Future<List<Place>> getNearbyPlaces({
required double latitude,
required double longitude,
required String type,
int radius = 5000,
}) async {
final response = await dio.get(
'${MapsConfig.baseUrl}${MapsConfig.endpoints['places']}',
queryParameters: {
'location': '$latitude,$longitude',
'radius': radius,
'type': type,
'key': MapsConfig.apiKey,
},
);
return Place.listFromJson(response.data['results']);
}
// Mobile Money Configuration
class MobileMoneyConfig {
static const String baseUrl = 'https://mm-gateway.exploreuganda.app/v1';
static const supportedProviders = ['MTN', 'Airtel'];
static Future<bool> initiatePayment({
required String phoneNumber,
required double amount,
required String provider,
}) async {
// Implementation
}
}
// Stripe Integration
class StripeService {
static const String publishableKey = 'YOUR_STRIPE_PUBLISHABLE_KEY';
static Future<PaymentIntent> createPaymentIntent({
required String currency,
required int amount,
}) async {
// Implementation
}
}
// PayPal Integration
class PayPalService {
static const String clientId = 'YOUR_PAYPAL_CLIENT_ID';
static Future<bool> processPayment({
required double amount,
required String currency,
}) async {
// Implementation
}
}
// Firebase Setup
final firebaseOptions = FirebaseOptions(
apiKey: 'YOUR_API_KEY',
appId: 'YOUR_APP_ID',
messagingSenderId: 'YOUR_SENDER_ID',
projectId: 'YOUR_PROJECT_ID',
);
// Initialize Firebase
await Firebase.initializeApp(options: firebaseOptions);
// Cloud Functions Integration
class CloudFunctions {
static final functions = FirebaseFunctions.instance;
static Future<void> processBooking(BookingData data) async {
try {
await functions
.httpsCallable('processBooking')
.call(data.toJson());
} catch (e) {
// Error handling
}
}
}
// FCM Configuration
class FCMConfig {
static final messaging = FirebaseMessaging.instance;
static Future<void> initialize() async {
final settings = await messaging.requestPermission();
final token = await messaging.getToken();
// Save token to backend
await updateFCMToken(token);
}
static Future<void> handleBackgroundMessage(
RemoteMessage message,
) async {
// Handle background message
}
}
class APIError {
final int code;
final String message;
final String? details;
APIError({
required this.code,
required this.message,
this.details,
});
factory APIError.fromJson(Map<String, dynamic> json) {
return APIError(
code: json['code'],
message: json['message'],
details: json['details'],
);
}
}
Future<T> handleApiCall<T>(Future<T> Function() apiCall) async {
try {
return await apiCall();
} on DioError catch (e) {
throw APIError(
code: e.response?.statusCode ?? 500,
message: e.response?.data['message'] ?? 'Unknown error occurred',
details: e.response?.data['details'],
);
} catch (e) {
throw APIError(
code: 500,
message: 'Internal error occurred',
);
}
}
class RateLimits {
static const Map<String, int> limits = {
'attractions': 100, // requests per minute
'events': 100,
'services': 100,
'search': 60,
'bookings': 30,
};
}
class APIVersion {
static const String current = 'v1';
static const List<String> supported = ['v1'];
static bool isSupported(String version) {
return supported.contains(version);
}
}
void main() {
group('API Integration Tests', () {
test('Get Attractions', () async {
final attractions = await getAttractions(
page: 1,
limit: 10,
);
expect(attractions, isNotEmpty);
});
test('User Profile', () async {
final profile = await getUserProfile();
expect(profile, isNotNull);
});
});
}
/// Generates Swagger/OpenAPI documentation
void generateApiDocs() {
// Implementation
}