| # API Client Usage Guide |
|
|
| This guide shows how to use the API client for making authenticated requests to the Nepal Justice Weaver backend. |
|
|
| ## Backend API Information |
|
|
| - **Base URL:** `http://localhost:8000` |
| - **API Prefix:** `/api/v1` |
| - **Authentication:** Supabase Auth with JWT tokens |
|
|
| ## Basic Setup |
|
|
| The API client is already configured and can be imported from `@/lib/api-client`: |
|
|
| ```typescript |
| import { apiClient } from "@/lib/api-client" |
| import { setAuthData, getAccessToken, clearAuthData } from "@/lib/auth-utils" |
| ``` |
|
|
| ## Authentication |
|
|
| ### Register (Sign Up) |
| **Endpoint:** `POST /api/v1/auth/signup` |
|
|
| The registration now accepts only basic information: |
|
|
| ```typescript |
| import { apiClient } from "@/lib/api-client" |
| import { setAuthData } from "@/lib/auth-utils" |
| |
| try { |
| const response = await apiClient.register( |
| "john@example.com", // email |
| "securePassword123", // password (min 6 characters) |
| "John Doe" // full_name |
| ) |
| |
| // Response: { access_token, refresh_token?, user } |
| setAuthData(response.access_token, response.refresh_token, response.user) |
| |
| console.log("Registered successfully:", response.user) |
| } catch (error) { |
| console.error("Registration failed:", error.message) |
| } |
| ``` |
|
|
| ### Login |
| **Endpoint:** `POST /api/v1/auth/login` |
|
|
| ```typescript |
| import { apiClient } from "@/lib/api-client" |
| import { setAuthData } from "@/lib/auth-utils" |
| |
| try { |
| const response = await apiClient.login( |
| "john@example.com", |
| "securePassword123" |
| ) |
| |
| // Store authentication data |
| setAuthData(response.access_token, response.refresh_token, response.user) |
| |
| console.log("Logged in successfully:", response.user) |
| } catch (error) { |
| console.error("Login failed:", error.message) |
| } |
| ``` |
|
|
| ### Logout |
| ```typescript |
| import { clearAuthData } from "@/lib/auth-utils" |
| |
| // Clear all authentication data from localStorage |
| clearAuthData() |
| |
| // Optionally redirect to login page |
| router.push("/login") |
| ``` |
|
|
| ## Protected Features |
|
|
| These features require authentication (access token must be stored in localStorage). |
|
|
| ### 1. Letter Generation |
| **Endpoint:** `POST /api/v1/letter/generate` (requires auth) |
|
|
| Generate legal letters based on user input: |
|
|
| ```typescript |
| try { |
| const response = await apiClient.post("/api/v1/letter/generate", { |
| letterType: "complaint", |
| recipientName: "District Court", |
| subject: "Property Dispute", |
| details: "Description of the legal matter..." |
| }) |
| |
| console.log("Generated letter:", response) |
| } catch (error) { |
| console.error("Letter generation failed:", error.message) |
| } |
| ``` |
|
|
| ### 2. Law Explanation Chatbot |
| **Endpoint:** `POST /api/v1/law-explanation/chat` (requires auth) |
|
|
| Get explanations about Nepali laws: |
|
|
| ```typescript |
| try { |
| const response = await apiClient.post("/api/v1/law-explanation/chat", { |
| query: "What are my rights as a tenant in Nepal?", |
| context: "rental agreement dispute" |
| }) |
| |
| console.log("Chatbot response:", response) |
| } catch (error) { |
| console.error("Chatbot request failed:", error.message) |
| } |
| ``` |
|
|
| ### 3. Bias Detection |
| **Endpoint:** `POST /api/v1/bias-detection/analyze` (requires auth) |
|
|
| Analyze legal documents or text for potential bias: |
|
|
| ```typescript |
| try { |
| const response = await apiClient.post("/api/v1/bias-detection/analyze", { |
| text: "Legal document text to analyze for bias...", |
| documentType: "court_decision" |
| }) |
| |
| console.log("Bias analysis:", response) |
| } catch (error) { |
| console.error("Bias detection failed:", error.message) |
| } |
| ``` |
|
|
| ## Generic Protected Requests |
|
|
| The API client provides generic methods for protected endpoints: |
|
|
| ### GET Request |
| ```typescript |
| try { |
| const data = await apiClient.get("/api/v1/some-endpoint") |
| console.log("Data:", data) |
| } catch (error) { |
| console.error("Failed:", error.message) |
| } |
| ``` |
|
|
| ### POST Request |
| ```typescript |
| try { |
| const result = await apiClient.post("/api/v1/some-endpoint", { |
| field1: "value1", |
| field2: "value2" |
| }) |
| console.log("Result:", result) |
| } catch (error) { |
| console.error("Failed:", error.message) |
| } |
| ``` |
|
|
| ### PUT Request |
| ```typescript |
| try { |
| const updated = await apiClient.put("/api/v1/some-endpoint", { |
| field: "updated value" |
| }) |
| console.log("Updated:", updated) |
| } catch (error) { |
| console.error("Failed:", error.message) |
| } |
| ``` |
|
|
| ### DELETE Request |
| ```typescript |
| try { |
| const result = await apiClient.delete("/api/v1/some-endpoint") |
| console.log("Deleted:", result) |
| } catch (error) { |
| console.error("Failed:", error.message) |
| } |
| ``` |
|
|
| ## Using in React Components |
|
|
| ### Example: Fetching Data on Component Mount |
| ```typescript |
| "use client" |
| |
| import { useEffect, useState } from "react" |
| import { apiClient } from "@/lib/api-client" |
| |
| export default function ProfilePage() { |
| const [profile, setProfile] = useState(null) |
| const [loading, setLoading] = useState(true) |
| const [error, setError] = useState(null) |
| |
| useEffect(() => { |
| const fetchProfile = async () => { |
| try { |
| const data = await apiClient.get("/users/me") |
| setProfile(data) |
| } catch (err) { |
| setError(err.message) |
| } finally { |
| setLoading(false) |
| } |
| } |
| |
| fetchProfile() |
| }, []) |
| |
| if (loading) return <div>Loading...</div> |
| if (error) return <div>Error: {error}</div> |
| |
| return <div>Welcome, {profile?.name}</div> |
| } |
| ``` |
|
|
| ### Example: Form Submission |
| ```typescript |
| "use client" |
| |
| import { useState } from "react" |
| import { apiClient } from "@/lib/api-client" |
| |
| export default function CreateQueryForm() { |
| const [title, setTitle] = useState("") |
| const [description, setDescription] = useState("") |
| const [loading, setLoading] = useState(false) |
| const [error, setError] = useState(null) |
| |
| const handleSubmit = async (e) => { |
| e.preventDefault() |
| setLoading(true) |
| setError(null) |
| |
| try { |
| const result = await apiClient.post("/legal-queries", { |
| title, |
| description |
| }) |
| console.log("Query created:", result) |
| // Reset form or redirect |
| setTitle("") |
| setDescription("") |
| } catch (err) { |
| setError(err.message) |
| } finally { |
| setLoading(false) |
| } |
| } |
| |
| return ( |
| <form onSubmit={handleSubmit}> |
| <input |
| value={title} |
| onChange={(e) => setTitle(e.target.value)} |
| placeholder="Title" |
| /> |
| <textarea |
| value={description} |
| onChange={(e) => setDescription(e.target.value)} |
| placeholder="Description" |
| /> |
| {error && <div className="error">{error}</div>} |
| <button type="submit" disabled={loading}> |
| {loading ? "Submitting..." : "Submit"} |
| </button> |
| </form> |
| ) |
| } |
| ``` |
|
|
| ## Authentication Utilities |
|
|
| The `@/lib/auth-utils` module provides helper functions for managing authentication: |
|
|
| ### Store Authentication Data |
| ```typescript |
| import { setAuthData } from "@/lib/auth-utils" |
| |
| // Store access token, refresh token, and user info |
| setAuthData(accessToken, refreshToken, userData) |
| ``` |
|
|
| ### Get Access Token |
| ```typescript |
| import { getAccessToken } from "@/lib/auth-utils" |
| |
| const token = getAccessToken() |
| if (token) { |
| console.log("User is authenticated") |
| } |
| ``` |
|
|
| ### Get Refresh Token |
| ```typescript |
| import { getRefreshToken } from "@/lib/auth-utils" |
| |
| const refreshToken = getRefreshToken() |
| ``` |
|
|
| ### Get User Data |
| ```typescript |
| import { getUser } from "@/lib/auth-utils" |
| |
| const user = getUser() |
| if (user) { |
| console.log("User email:", user.email) |
| } |
| ``` |
|
|
| ### Check Authentication Status |
| ```typescript |
| import { isAuthenticated } from "@/lib/auth-utils" |
| |
| if (isAuthenticated()) { |
| // User has valid access token |
| // Allow access to protected features |
| } else { |
| // Redirect to login |
| router.push("/login") |
| } |
| ``` |
|
|
| ### Clear Authentication (Logout) |
| ```typescript |
| import { clearAuthData } from "@/lib/auth-utils" |
| |
| // Remove all auth data from localStorage |
| clearAuthData() |
| ``` |
|
|
| ## Token Storage Details |
|
|
| Authentication data is stored in localStorage with these keys: |
| - `access_token` - JWT access token from Supabase |
| - `refresh_token` - JWT refresh token (optional) |
| - `user` - JSON stringified user object |
|
|
| The access token is automatically: |
| - Stored when you register or login |
| - Included in all authenticated requests with the `Authorization: Bearer <token>` header |
| - Retrieved from localStorage for each protected request |
|
|
| ## Error Handling |
|
|
| The API client throws errors with meaningful messages: |
| - **Network errors**: Connection failures |
| - **API errors**: Returns the `detail` field from backend response |
| - **Validation errors**: Invalid input or missing required fields |
| - **Authentication errors**: Invalid or expired token (401) |
|
|
| Always wrap API calls in try-catch blocks to handle errors gracefully: |
|
|
| ```typescript |
| try { |
| const result = await apiClient.post("/api/v1/some-endpoint", data) |
| } catch (error) { |
| if (error instanceof Error) { |
| // Display user-friendly error message |
| toast.error(error.message) |
| } |
| } |
| ``` |
|
|
| ## Environment Variables |
|
|
| Set the backend URL in your `.env.local` file: |
|
|
| ```bash |
| NEXT_PUBLIC_BACKEND_URL=http://localhost:8000 |
| ``` |
|
|
| If not set, it defaults to `http://localhost:8000`. |
|
|
| ## Summary |
|
|
| **Registration Flow:** |
| 1. User fills out registration form with name, email, password |
| 2. Form validates password match and minimum length |
| 3. Call `apiClient.register(email, password, name)` |
| 4. Store tokens with `setAuthData(access_token, refresh_token, user)` |
| 5. Redirect to dashboard |
|
|
| **Login Flow:** |
| 1. User enters email and password |
| 2. Call `apiClient.login(email, password)` |
| 3. Store tokens with `setAuthData(access_token, refresh_token, user)` |
| 4. Redirect to dashboard |
|
|
| **Using Protected Features:** |
| 1. Check authentication with `isAuthenticated()` |
| 2. Make API calls to letter generation, chatbot, or bias detection endpoints |
| 3. API client automatically includes the Bearer token |
| 4. Handle success/error responses appropriately |
|
|