API Usage Examples
This document provides practical examples of common API usage scenarios using various tools like cURL, JavaScript, and Go.
Authentication Flow
1. Register a New User
cURL Example:
curl -X POST http://localhost:3000/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "securepassword123", "first_name": "John", "last_name": "Doe" }'
JavaScript Example (Fetch API):
fetch('http://localhost:3000/api/v1/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ password: 'securepassword123', first_name: 'John', last_name: 'Doe' }),}).then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));
Go Example:
package main
import ( "bytes" "encoding/json" "fmt" "net/http")
func main() { // Create request body requestBody, err := json.Marshal(map[string]string{ "password": "securepassword123", "first_name": "John", "last_name": "Doe", }) if err != nil { fmt.Println("Error creating request body:", err) return }
// Make the request resp, err := http.Post( "http://localhost:3000/api/v1/auth/register", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { fmt.Println("Error making request:", err) return } defer resp.Body.Close()
// Parse the response var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) fmt.Println("Response:", result)}
2. Verify Email
After registration, the user will receive a verification token. Use this to verify their email:
cURL Example:
curl -X POST http://localhost:3000/api/v1/auth/verify-email \ -H "Content-Type: application/json" \ -d '{ "token": "verification-token-received-via-email" }'
3. Login
cURL Example:
curl -X POST http://localhost:3000/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "password": "securepassword123" }'
Response:
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer", "expires_in": 900}
JavaScript Example (Fetch API):
fetch('http://localhost:3000/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ password: 'securepassword123' }),}).then(response => response.json()).then(data => { // Store tokens in localStorage or securely in memory localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); console.log('Authentication successful:', data);}).catch(error => console.error('Error:', error));
Go Example:
package main
import ( "bytes" "encoding/json" "fmt" "net/http")
func main() { // Create request body requestBody, err := json.Marshal(map[string]string{ "password": "securepassword123", }) if err != nil { fmt.Println("Error creating request body:", err) return }
// Make the request resp, err := http.Post( "http://localhost:3000/api/v1/auth/login", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { fmt.Println("Error making request:", err) return } defer resp.Body.Close()
// Parse the response var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) fmt.Println("Access Token:", result["access_token"]) fmt.Println("Refresh Token:", result["refresh_token"])}
4. Refresh Token
When the access token expires, use the refresh token to get a new pair:
cURL Example:
curl -X POST http://localhost:3000/api/v1/auth/refresh \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }'
JavaScript Example:
fetch('http://localhost:3000/api/v1/auth/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: localStorage.getItem('refresh_token') }),}).then(response => response.json()).then(data => { // Update tokens in storage localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); console.log('Tokens refreshed successfully');}).catch(error => console.error('Error refreshing tokens:', error));
5. Logout
cURL Example:
curl -X POST http://localhost:3000/api/v1/auth/logout \ -H "Content-Type: application/json" \ -d '{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." }'
JavaScript Example:
fetch('http://localhost:3000/api/v1/auth/logout', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: localStorage.getItem('refresh_token') }),}).then(response => { if (response.ok) { // Clear tokens from storage localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); console.log('Logged out successfully'); } else { console.error('Logout failed'); }}).catch(error => console.error('Error during logout:', error));
User Management
1. Get Current User Profile
cURL Example:
curl -X GET http://localhost:3000/api/v1/users/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
JavaScript Example:
fetch('http://localhost:3000/api/v1/users/me', { method: 'GET', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, },}).then(response => response.json()).then(data => console.log('User profile:', data)).catch(error => console.error('Error fetching profile:', error));
2. Update User Profile
cURL Example:
curl -X PUT http://localhost:3000/api/v1/users/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "first_name": "Updated", "last_name": "Name" }'
JavaScript Example:
fetch('http://localhost:3000/api/v1/users/me', { method: 'PUT', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ first_name: 'Updated', last_name: 'Name' }),}).then(response => response.json()).then(data => console.log('Updated profile:', data)).catch(error => console.error('Error updating profile:', error));
3. List All Users (Admin Only)
cURL Example:
curl -X GET "http://localhost:3000/api/v1/users?page=1&per_page=20" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
JavaScript Example:
fetch('http://localhost:3000/api/v1/users?page=1&per_page=20', { method: 'GET', headers: { 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, },}).then(response => response.json()).then(data => console.log('Users list:', data)).catch(error => console.error('Error fetching users:', error));
API Key Management
1. Create an API Key
cURL Example:
curl -X POST http://localhost:3000/api/v1/api-keys \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "name": "My Service API Key", "expires_at": "2025-12-31T23:59:59Z" }'
Response:
{ "id": "8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d", "user_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b", "name": "My Service API Key", "key": "sk-Avery1LongRandomAPIKeyStringThatShouldBeStoredSafely", "prefix": "sk-Avery", "is_active": true, "expires_at": "2025-12-31T23:59:59Z", "created_at": "2023-06-01T12:34:56Z", "updated_at": "2023-06-01T12:34:56Z"}
Important: The full API key (key
field) is only returned once when creating the key. Store it securely as you won’t be able to retrieve it later.
2. List Your API Keys
cURL Example:
curl -X GET http://localhost:3000/api/v1/api-keys \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
3. Add Permissions to API Key
cURL Example:
curl -X POST http://localhost:3000/api/v1/api-keys/8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d/permissions \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "permission_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b" }'
4. Using an API Key for Authentication
Instead of using JWT tokens, you can authenticate with an API key:
cURL Example:
curl -X GET http://localhost:3000/api/v1/users/me \ -H "X-API-Key: sk-Avery1LongRandomAPIKeyStringThatShouldBeStoredSafely"
JavaScript Example:
fetch('http://localhost:3000/api/v1/users/me', { method: 'GET', headers: { 'X-API-Key': 'sk-Avery1LongRandomAPIKeyStringThatShouldBeStoredSafely', },}).then(response => response.json()).then(data => console.log('User profile:', data)).catch(error => console.error('Error fetching profile:', error));
Role and Permission Management
1. List All Roles
cURL Example:
curl -X GET http://localhost:3000/api/v1/roles \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
2. Create a New Role (Admin Only)
cURL Example:
curl -X POST http://localhost:3000/api/v1/roles \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "name": "editor", "description": "Can edit content but not manage users" }'
3. Add Permission to Role (Admin Only)
cURL Example:
curl -X POST http://localhost:3000/api/v1/roles/8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d/permissions \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "permission_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b" }'
4. Assign Role to User (Admin Only)
cURL Example:
curl -X POST http://localhost:3000/api/v1/users/8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d/roles \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \ -H "Content-Type: application/json" \ -d '{ "role_id": "5f8d0d55-8b96-4536-8c34-781a9a3e9a9b" }'
Error Handling Examples
1. Validation Error
Request:
curl -X POST http://localhost:3000/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{ "email": "invalid-email", "password": "short", "first_name": "John", "last_name": "Doe" }'
Response:
{ "error": "Validation failed", "fields": { "email": "must be a valid email address", "password": "must be at least 8 characters long" }}
2. Authentication Error
Request:
curl -X GET http://localhost:3000/api/v1/users/me
Response:
{ "error": "Unauthorized: missing authentication token", "status": 401}
3. Rate Limiting Error
When rate limits are exceeded:
Response:
{ "error": "Rate limit exceeded", "status": 429}
Helper Utilities
JavaScript Authentication Utility
Here’s a simple JavaScript utility for handling authentication:
class AuthService { constructor(apiUrl) { this.apiUrl = apiUrl; this.accessToken = localStorage.getItem('access_token'); this.refreshToken = localStorage.getItem('refresh_token'); }
isAuthenticated() { return !!this.accessToken; }
async login(email, password) { const response = await fetch(`${this.apiUrl}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ email, password }), });
if (!response.ok) { const error = await response.json(); throw new Error(error.error || 'Login failed'); }
const data = await response.json(); this.accessToken = data.access_token; this.refreshToken = data.refresh_token;
localStorage.setItem('access_token', this.accessToken); localStorage.setItem('refresh_token', this.refreshToken);
return data; }
async logout() { if (!this.refreshToken) return;
try { await fetch(`${this.apiUrl}/auth/logout`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: this.refreshToken }), }); } catch (error) { console.error('Logout error:', error); } finally { // Clear tokens regardless of logout success this.accessToken = null; this.refreshToken = null; localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); } }
async refreshAccessToken() { if (!this.refreshToken) throw new Error('No refresh token available');
const response = await fetch(`${this.apiUrl}/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refresh_token: this.refreshToken }), });
if (!response.ok) { // If refresh fails, log out this.logout(); throw new Error('Failed to refresh token'); }
const data = await response.json(); this.accessToken = data.access_token; this.refreshToken = data.refresh_token;
localStorage.setItem('access_token', this.accessToken); localStorage.setItem('refresh_token', this.refreshToken);
return data; }
async fetchWithAuth(url, options = {}) { const headers = { ...options.headers, 'Authorization': `Bearer ${this.accessToken}`, };
let response = await fetch(url, { ...options, headers });
// If unauthorized, try to refresh token and retry the request if (response.status === 401 && this.refreshToken) { try { await this.refreshAccessToken(); // Update headers with new token headers.Authorization = `Bearer ${this.accessToken}`; // Retry the request response = await fetch(url, { ...options, headers }); } catch (error) { console.error('Token refresh failed:', error); throw error; } }
return response; }}
// Usage:const auth = new AuthService('http://localhost:3000/api/v1');
async function loginUser(email, password) { try { await auth.login(email, password); console.log('Login successful'); } catch (error) { console.error('Login failed:', error); }}
async function getUserProfile() { try { const response = await auth.fetchWithAuth(`${auth.apiUrl}/users/me`); if (!response.ok) throw new Error('Failed to get profile'); const profile = await response.json(); console.log('User profile:', profile); return profile; } catch (error) { console.error('Error fetching profile:', error); }}
Go Client Example
Here’s a simple Go client for the API:
package main
import ( "bytes" "encoding/json" "errors" "fmt" "net/http")
// AuthClient represents a client for the auth APItype AuthClient struct { BaseURL string AccessToken string RefreshToken string HTTPClient *http.Client}
// NewAuthClient creates a new auth clientfunc NewAuthClient(baseURL string) *AuthClient { return &AuthClient{ BaseURL: baseURL, HTTPClient: &http.Client{}, }}
// TokenResponse represents the response from login and refresh endpointstype TokenResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` ExpiresIn int `json:"expires_in"`}
// Login authenticates a userfunc (c *AuthClient) Login(email, password string) error { // Create request body requestBody, err := json.Marshal(map[string]string{ "email": email, "password": password, }) if err != nil { return err }
// Make the request resp, err := c.HTTPClient.Post( c.BaseURL+"/auth/login", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { return err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { var errorResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&errorResp) return fmt.Errorf("login failed: %v", errorResp["error"]) }
// Parse the response var tokenResp TokenResponse if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { return err }
// Save tokens c.AccessToken = tokenResp.AccessToken c.RefreshToken = tokenResp.RefreshToken return nil}
// AuthenticatedRequest makes an authenticated requestfunc (c *AuthClient) AuthenticatedRequest(method, path string, body interface{}) (*http.Response, error) { if c.AccessToken == "" { return nil, errors.New("not authenticated") }
var bodyReader *bytes.Buffer if body != nil { bodyData, err := json.Marshal(body) if err != nil { return nil, err } bodyReader = bytes.NewBuffer(bodyData) }
// Create request req, err := http.NewRequest(method, c.BaseURL+path, bodyReader) if err != nil { return nil, err }
// Set headers req.Header.Set("Authorization", "Bearer "+c.AccessToken) if body != nil { req.Header.Set("Content-Type", "application/json") }
// Make the request resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err }
// If unauthorized, try to refresh token if resp.StatusCode == http.StatusUnauthorized && c.RefreshToken != "" { resp.Body.Close() // Close the 401 response
// Try to refresh token err = c.RefreshToken() if err != nil { return nil, fmt.Errorf("token refresh failed: %w", err) }
// Retry the request with new token req.Header.Set("Authorization", "Bearer "+c.AccessToken) return c.HTTPClient.Do(req) }
return resp, nil}
// RefreshToken refreshes the access tokenfunc (c *AuthClient) RefreshTokens() error { if c.RefreshToken == "" { return errors.New("no refresh token available") }
// Create request body requestBody, err := json.Marshal(map[string]string{ "refresh_token": c.RefreshToken, }) if err != nil { return err }
// Make the request resp, err := c.HTTPClient.Post( c.BaseURL+"/auth/refresh", "application/json", bytes.NewBuffer(requestBody), ) if err != nil { return err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { // Clear tokens on refresh failure c.AccessToken = "" c.RefreshToken = "" var errorResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&errorResp) return fmt.Errorf("token refresh failed: %v", errorResp["error"]) }
// Parse the response var tokenResp TokenResponse if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { return err }
// Save new tokens c.AccessToken = tokenResp.AccessToken c.RefreshToken = tokenResp.RefreshToken return nil}
// GetUserProfile gets the current user's profilefunc (c *AuthClient) GetUserProfile() (map[string]interface{}, error) { resp, err := c.AuthenticatedRequest("GET", "/users/me", nil) if err != nil { return nil, err } defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { var errorResp map[string]interface{} json.NewDecoder(resp.Body).Decode(&errorResp) return nil, fmt.Errorf("failed to get profile: %v", errorResp["error"]) }
var profile map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&profile); err != nil { return nil, err }
return profile, nil}
// Usage examplefunc main() { client := NewAuthClient("http://localhost:3000/api/v1")
// Login if err != nil { fmt.Println("Login error:", err) return }
// Get profile profile, err := client.GetUserProfile() if err != nil { fmt.Println("Error getting profile:", err) return }
fmt.Println("User profile:", profile)}