API Overview
Comprehensive guide to the WI-CARPOOL API endpoints, authentication, and integration
Introduction
The WI-CARPOOL application communicates with a RESTful API backend to handle all data operations including user authentication, ride management, payments, and messaging. This section provides comprehensive documentation for all API endpoints and integration patterns.
API Base URL: The default API base URL is configured in
src/api/constants.ts
as https://pool.prattle.me/
API Architecture
Service Layer Structure
The application uses a service layer architecture to organize API calls:
Service Files Structure
src/api/
├── axiosInstance.ts # Axios configuration and interceptors
├── constants.ts # API endpoints and configurations
├── index.ts # Main API exports
└── services/
├── authService.ts # Authentication endpoints
├── rideService.ts # Ride management endpoints
├── profileService.ts # User profile endpoints
├── paymentService.ts # Payment processing endpoints
├── walletService.ts # Wallet operations endpoints
├── driverService.ts # Driver-specific endpoints
├── chatService.ts # Messaging endpoints
├── commonService.ts # Common utility endpoints
├── preferencesService.ts # User preferences endpoints
├── ratingService.ts # Rating system endpoints
└── availableRidesService.ts # Available rides endpoints
HTTP Client Configuration
Axios Instance (src/api/axiosInstance.ts)
import axios from 'axios';
import { AppConstants } from './constants';
const axiosInstance = axios.create({
baseURL: AppConstants.baseUrl,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
});
// Request interceptor for authentication
axiosInstance.interceptors.request.use(
(config) => {
const token = localStorage.getItem('userToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// Response interceptor for error handling
axiosInstance.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem('userToken');
window.location.href = '/signin';
}
return Promise.reject(error);
}
);
export default axiosInstance;
API Endpoints
All API endpoints are centrally defined in the constants file:
API Constants (src/api/constants.ts)
export const AppConstants = {
// Base Configuration
baseUrl: "https://pool.prattle.me/",
// Authentication Endpoints
login: "login",
register: "register",
verifyOtp: "verify_otp",
resendOtp: "resend_otp",
forgotPassword: "forgot_password",
resetPassword: "reset_password",
// User Profile Endpoints
getUserProfile: "get_user_profile",
updateUserProfile: "update_user_profile",
uploadProfileImage: "upload_profile_image",
// Ride Management Endpoints
createRide: "create_ride",
updateRide: "update_ride",
deleteRide: "delete_ride",
getRides: "get_rides",
searchRides: "search_rides",
bookRide: "book_ride",
cancelBooking: "cancel_booking",
// Driver Endpoints
driverRides: "driver_rides",
updateLocation: "update_location",
checkStatus: "check_status",
getPendingTrips: "get_pending_trips",
getCompletedTrips: "get_completed_trips",
acceptRequest: "accept_request",
beginTrip: "begin_trip",
endTrip: "end_trip",
arriveNow: "arrive_now",
// Payment Endpoints
getPaymentList: "get_payment_list",
addWallet: "add_wallet",
cashoutWallet: "cashout_wallet",
afterPayment: "after_payment",
addCardDetails: "add_card_details",
getCardDetails: "get_card_details",
// Messaging Endpoints
sendMessage: "send_message",
getMessages: "get_messages",
getChatList: "get_chat_list",
// Common Endpoints
commonData: "common_data",
countryList: "country_list",
currencyList: "currency_list",
uploadImage: "upload_image",
// Rating Endpoints
driverRating: "driver_rating",
riderFeedback: "rider_feedback",
getTripRating: "get_trip_rating",
};
Authentication
Authentication Flow
WI-CARPOOL uses token-based authentication with the following flow:
- User registers or logs in with phone number
- OTP verification for phone number validation
- Server returns JWT token upon successful verification
- Token is stored in localStorage and included in subsequent requests
- Token refresh handled automatically by axios interceptors
Request Authentication
Token Usage Example
// Token is automatically added by axios interceptor
// Manual token usage for non-axios requests:
const token = localStorage.getItem('userToken');
const response = await fetch(`${AppConstants.baseUrl}get_user_profile`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
Authentication Service Example
Login Implementation
// src/api/services/authService.ts
export const authService = {
login: async (phoneNumber: string, countryCode: string) => {
const response = await axiosInstance.post(AppConstants.login, {
phone_number: phoneNumber,
country_code: countryCode
});
return response.data;
},
verifyOtp: async (phoneNumber: string, otp: string) => {
const response = await axiosInstance.post(AppConstants.verifyOtp, {
phone_number: phoneNumber,
otp: otp
});
// Store token on successful verification
if (response.data.token) {
localStorage.setItem('userToken', response.data.token);
}
return response.data;
}
};
Data Flow Patterns
React Query Integration
The application uses TanStack React Query for efficient data fetching and caching:
Query Example
import { useQuery } from '@tanstack/react-query';
import { profileService } from '@/api/services/profileService';
const ProfileComponent = () => {
const { data: profileData, isLoading, error } = useQuery({
queryKey: ['userProfile', user?.token],
queryFn: () => profileService.getCurrentUserProfile(user.token),
enabled: !!user?.token,
staleTime: 5 * 60 * 1000, // 5 minutes
cacheTime: 10 * 60 * 1000, // 10 minutes
});
if (isLoading) return Loading...;
if (error) return Error loading profile;
return {profileData?.first_name};
};
Mutation Example
Data Mutation with React Query
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { profileService } from '@/api/services/profileService';
const useUpdateProfile = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: profileService.updateProfile,
onSuccess: (data) => {
// Invalidate and refetch profile data
queryClient.invalidateQueries(['userProfile']);
// Show success toast
toast.success('Profile updated successfully');
},
onError: (error) => {
console.error('Profile update failed:', error);
toast.error('Failed to update profile');
},
});
};
Error Handling
Standard Error Response Format
API Error Response Structure
{
"status_code": "0",
"status_message": "Error description",
"error_details": {
"field": "error_message",
"code": "ERROR_CODE"
}
}
Error Handling Implementation
Service Error Handling
// src/api/services/baseService.ts
export const handleApiError = (error: any) => {
if (error.response) {
// Server responded with error status
const { status, data } = error.response;
switch (status) {
case 400:
throw new Error(data.status_message || 'Bad Request');
case 401:
localStorage.removeItem('userToken');
window.location.href = '/signin';
throw new Error('Unauthorized access');
case 403:
throw new Error('Access forbidden');
case 404:
throw new Error('Resource not found');
case 500:
throw new Error('Server error. Please try again later.');
default:
throw new Error(data.status_message || 'An error occurred');
}
} else if (error.request) {
// Network error
throw new Error('Network error. Please check your connection.');
} else {
// Other error
throw new Error(error.message || 'An unexpected error occurred');
}
};
Request/Response Examples
User Registration
Request
POST /register
Content-Type: application/json
{
"first_name": "John",
"last_name": "Doe",
"email": "[email protected]",
"phone_number": "1234567890",
"country_code": "+1",
"password": "securepassword123",
"user_type": "passenger"
}
Response
{
"status_code": "1",
"status_message": "Registration successful",
"data": {
"user_id": "12345",
"otp_sent": true,
"verification_required": true
}
}
Get Available Rides
Request
GET /search_rides?pickup_location=New York&drop_location=Boston&date=2024-01-15
Authorization: Bearer {token}
Response
{
"status_code": "1",
"status_message": "Rides found",
"rides": [
{
"id": 123,
"pickup_location": "New York, NY",
"drop_location": "Boston, MA",
"pickup_time": "08:00",
"depart_date": "2024-01-15",
"price_per_person": "45.00",
"available_seats": 3,
"driver_name": "Jane Smith",
"driver_rating": 4.8,
"car_model": "Toyota Camry",
"amenities": ["WiFi", "AC", "Music"]
}
]
}
Rate Limiting & Best Practices
Rate Limiting
The API implements rate limiting to ensure fair usage:
- Authentication endpoints: 5 requests per minute
- Search endpoints: 60 requests per minute
- General endpoints: 100 requests per minute
- File upload endpoints: 10 requests per minute
Best Practices
- Use React Query: Leverage caching and background updates
- Implement retry logic: Handle temporary network failures
- Debounce search requests: Avoid excessive API calls
- Cache static data: Store countries, currencies, etc. locally
- Handle offline scenarios: Provide graceful degradation
Debounced Search Example
import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { debounce } from 'lodash';
const SearchComponent = () => {
const [searchTerm, setSearchTerm] = useState('');
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('');
// Debounce search term
useEffect(() => {
const handler = debounce(() => {
setDebouncedSearchTerm(searchTerm);
}, 500);
handler();
return () => {
handler.cancel();
};
}, [searchTerm]);
// Query with debounced term
const { data: searchResults } = useQuery({
queryKey: ['searchRides', debouncedSearchTerm],
queryFn: () => rideService.searchRides(debouncedSearchTerm),
enabled: debouncedSearchTerm.length > 2,
});
return (
setSearchTerm(e.target.value)}
placeholder="Search rides..."
/>
);
};
API Testing
Testing Tools
- Postman: For manual API testing and documentation
- Thunder Client: VS Code extension for API testing
- Jest + MSW: For automated API mocking in tests
- React Query Devtools: For debugging query behavior
Mock Service Worker Setup
MSW Configuration for Testing
// src/mocks/handlers.ts
import { rest } from 'msw';
import { AppConstants } from '@/api/constants';
export const handlers = [
rest.get(`${AppConstants.baseUrl}${AppConstants.getUserProfile}`, (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
status_code: "1",
status_message: "Success",
first_name: "John",
last_name: "Doe",
email: "[email protected]"
})
);
}),
rest.post(`${AppConstants.baseUrl}${AppConstants.login}`, (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
status_code: "1",
status_message: "Login successful",
token: "mock-jwt-token"
})
);
}),
];
API Versioning
Version Strategy
The WI-CARPOOL API uses URL-based versioning:
Version Configuration
// Current API version
export const API_VERSION = 'v1';
// Versioned endpoints
export const AppConstants = {
baseUrl: `https://pool.prattle.me/api/${API_VERSION}/`,
// ... rest of endpoints
};
// Version compatibility check
export const checkApiCompatibility = async () => {
try {
const response = await fetch(`${AppConstants.baseUrl}version`);
const { version, minimumClientVersion } = await response.json();
if (version !== API_VERSION) {
console.warn(`API version mismatch. Expected: ${API_VERSION}, Got: ${version}`);
}
return true;
} catch (error) {
console.error('Failed to check API compatibility:', error);
return false;
}
};