Skip to main content

Overview

Poway Auto integrates with a backend API hosted at autonomous.stu.nighthawkcodingsociety.com for user authentication, route planning, location verification, and data storage.

API Configuration

Base Configuration

The API configuration is centralized in assets/js/api/config.js (config.js:1-61).
export var pythonURI;
if (location.hostname === "localhost") {
    pythonURI = "http://localhost:8888";
} else if (location.hostname === "127.0.0.1") {
    pythonURI = "http://127.0.0.1:8888";
} else {
    pythonURI = "https://autonomous.stu.nighthawkcodingsociety.com";
}

export var javaURI;
if (location.hostname === "localhost") {
    javaURI = "http://localhost:8888";
} else if (location.hostname === "127.0.0.1") {
    javaURI = "http://127.0.0.1:8888";
} else {
    javaURI = "https://autonomous.stu.nighthawkcodingsociety.com";
}
Environment detection:
  • Development: localhost:8888 or 127.0.0.1:8888
  • Production: autonomous.stu.nighthawkcodingsociety.com

Default Fetch Options

export const fetchOptions = {
    method: 'GET',
    mode: 'cors',
    cache: 'default',
    credentials: 'include',
    headers: {
        'Content-Type': 'application/json',
        'X-Origin': 'client'
    },
};
Key settings:
  • mode: 'cors' - Enables Cross-Origin Resource Sharing
  • credentials: 'include' - Sends cookies with requests for authentication
  • X-Origin: 'client' - Custom header to identify frontend requests

CORS Setup

Frontend Configuration

All API requests include CORS headers to enable cross-origin communication:
const fetchOptions = {
    method: 'GET',
    mode: 'cors',
    credentials: 'include',
    headers: {
        'Content-Type': 'application/json'
    }
};

Backend Requirements

The backend must respond with appropriate CORS headers:
Access-Control-Allow-Origin: https://ahaanv19.github.io
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Origin

Authentication

Login Flow

The login function in config.js (config.js:29-60) handles user authentication:
export function login(options) {
    const requestOptions = {
        ...fetchOptions,
        method: options.method,
        cache: options.cache,
        body: JSON.stringify(options.body)
    };

    document.getElementById(options.message).textContent = "";

    fetch(options.URL, requestOptions)
    .then(response => {
        if (!response.ok) {
            const errorMsg = 'Login error: ' + response.status;
            console.log(errorMsg);
            document.getElementById(options.message).textContent = errorMsg;
            return;
        }
        options.callback();
    })
    .catch(error => {
        console.log('Possible CORS or Service Down error: ' + error);
        document.getElementById(options.message).textContent = 
            'Possible CORS or service down error: ' + error;
    });
}
Usage example:
import { pythonURI, login } from './assets/js/api/config.js';

login({
    URL: `${pythonURI}/api/authenticate`,
    method: 'POST',
    cache: 'no-cache',
    body: {
        username: '[email protected]',
        password: 'password123'
    },
    message: 'login-message',
    callback: () => {
        window.location.href = '/profile';
    }
});

Session Management

The base layout (base.html:109-144) checks authentication status on page load:
import { pythonURI, javaURI, fetchOptions, login } from '{{site.baseurl}}/assets/js/api/config.js';

window.onload = async function () {
    const button = document.getElementById("sign-in-btn");
    try {
        const currentUserResponse = await fetch(
            `${pythonURI}/api/user`, 
            fetchOptions
        );
        if (!currentUserResponse.ok) {
            throw new Error('Failed to fetch current user');
        }
        const currentUser = await currentUserResponse.json();
        button.textContent = currentUser.name || "Profile";
        button.href = "{{site.baseurl}}/profile";
        console.log(currentUser.uid);
    } catch (error) {
        button.textContent = "Sign In";
        button.href = "{{site.baseurl}}/login";
        console.log("error: ", error);
    }
}
Flow:
  1. On page load, fetch current user from /api/user
  2. If authenticated, display user name and link to profile
  3. If not authenticated, show “Sign In” button
  4. Session maintained via cookies (credentials: ‘include’)

API Endpoints

User Authentication

Get Current User:
GET /api/user
Response:
{
    "uid": "user123",
    "name": "John Doe",
    "email": "[email protected]"
}
Authenticate:
POST /api/authenticate
Content-Type: application/json

{
    "username": "[email protected]",
    "password": "password123"
}

Route Planning

From navigation/findBestRoute/map.js (map.js:1-88):
import { pythonURI } from '../../assets/js/api/config.js';

const apiUrl = `${pythonURI}/api/get_routes`;

const response = await fetch(apiUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ origin, destination, mode }),
});

const routes = await response.json();
Endpoint:
POST /api/get_routes
Request:
{
    "origin": "Poway, CA",
    "destination": "Qualcomm, San Diego",
    "mode": "driving"
}
Response:
[
    {
        "total_distance": "15.2 miles",
        "total_duration": "25 mins",
        "traffic_adjusted_duration": "32 mins",
        "geometry": "encoded_polyline_string",
        "details": [
            {
                "instruction": "Head north on Poway Rd",
                "distance": "0.5 miles",
                "duration": "2 mins"
            }
        ]
    }
]

Location Verification

From navigation/verify.html (verify.html:80-147):
const API_BASE = 'https://autonomous.stu.nighthawkcodingsociety.com/api';

const fetchOptions = {
    method: 'GET',
    mode: 'cors',
    cache: 'default',
    credentials: 'include',
    headers: {
        'Content-Type': 'application/json'
    }
};

// Submit entry
const res = await fetch(`${API_BASE}/entries`, {
    ...fetchOptions,
    method: 'POST',
    body: JSON.stringify({ name, email, address })
});

// Get all entries
const res = await fetch(`${API_BASE}/entries`, fetchOptions);
const data = await res.json();
Submit Entry:
POST /api/entries
Request:
{
    "name": "Jane Smith",
    "email": "[email protected]",
    "address": "123 Main St, Poway, CA 92064"
}
Get Entries:
GET /api/entries
Response:
[
    {
        "id": 1,
        "name": "Jane Smith",
        "email": "[email protected]",
        "address": "123 Main St, Poway, CA 92064",
        "created_at": "2025-03-04T10:30:00Z"
    }
]

Fetch Patterns

Basic GET Request

import { pythonURI, fetchOptions } from './assets/js/api/config.js';

const response = await fetch(`${pythonURI}/api/endpoint`, fetchOptions);

if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
}

const data = await response.json();

POST Request

import { pythonURI, fetchOptions } from './assets/js/api/config.js';

const response = await fetch(`${pythonURI}/api/endpoint`, {
    ...fetchOptions,
    method: 'POST',
    body: JSON.stringify({
        key: 'value'
    })
});

const data = await response.json();

Error Handling

try {
    const response = await fetch(`${pythonURI}/api/endpoint`, fetchOptions);
    
    if (!response.ok) {
        const error = await response.json();
        throw new Error(error.message || 'Request failed');
    }
    
    const data = await response.json();
    // Handle success
    
} catch (error) {
    console.error('API Error:', error);
    // Handle CORS, network, or API errors
    document.getElementById('error-message').textContent = 
        'Service unavailable. Please try again later.';
}

Route Visualization Example

From map.js (map.js:21-73):
document.getElementById('fetch_routes_btn').addEventListener('click', async () => {
    const origin = document.getElementById('origin').value;
    const destination = document.getElementById('destination').value;
    const mode = document.getElementById('mode').value || 'driving';

    if (!origin || !destination) {
        alert('Please enter both origin and destination.');
        return;
    }

    const response = await fetch(apiUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ origin, destination, mode }),
    });

    const routes = await response.json();
    const resultDiv = document.getElementById('result');
    resultDiv.innerHTML = '';

    if (!Array.isArray(routes)) {
        resultDiv.innerHTML = `<p>Error: ${routes.error || 'No routes found'}</p>`;
        return;
    }

    // Clear previous polylines
    polylines.forEach(p => map.removeLayer(p));
    polylines = [];

    routes.forEach((route, idx) => {
        // Display route info
        const header = document.createElement('h4');
        header.textContent = `Route ${idx + 1} - ${route.total_distance} - Est. Time: ${route.traffic_adjusted_duration || route.total_duration}`;
        resultDiv.appendChild(header);

        // Draw polyline on map
        if (route.geometry) {
            const decoded = polyline.decode(route.geometry);
            const polylineLayer = L.polyline(decoded, {
                color: idx === 0 ? 'blue' : 'gray',
                weight: 4,
                opacity: 0.8,
            }).addTo(map);
            polylines.push(polylineLayer);
            if (idx === 0) map.fitBounds(polylineLayer.getBounds());
        }
    });
});

Testing APIs

Local Development

  1. Start backend server:
    # Backend should run on port 8888
    python main.py
    
  2. Start frontend:
    make
    
  3. Test endpoints:
    // Will use http://localhost:8888
    fetch(`${pythonURI}/api/user`, fetchOptions)
    

Production Testing

# Test public endpoint
curl https://autonomous.stu.nighthawkcodingsociety.com/api/entries

# Test with credentials
curl -X POST https://autonomous.stu.nighthawkcodingsociety.com/api/authenticate \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"test"}' \
  --cookie-jar cookies.txt

# Authenticated request
curl https://autonomous.stu.nighthawkcodingsociety.com/api/user \
  --cookie cookies.txt

Best Practices

1. Always Import from Config

// Good
import { pythonURI, fetchOptions } from './assets/js/api/config.js';

// Bad - hardcoded URL
const API_URL = 'https://autonomous.stu.nighthawkcodingsociety.com';

2. Handle Errors Gracefully

try {
    const response = await fetch(url, options);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return await response.json();
} catch (error) {
    console.error('API Error:', error);
    // Show user-friendly message
    showErrorMessage('Unable to connect to server');
}

3. Use Credentials for Auth

const options = {
    ...fetchOptions,
    credentials: 'include'  // Required for cookies
};

4. Include CORS Headers

headers: {
    'Content-Type': 'application/json',
    'X-Origin': 'client'
}

Troubleshooting

CORS Errors

Error: Access to fetch at '...' from origin '...' has been blocked by CORS policy Solution:
  • Verify backend CORS headers include your origin
  • Check credentials: 'include' is set
  • Ensure backend allows credentials

Authentication Issues

Error: Failed to fetch current user Solution:
  • Clear cookies and log in again
  • Check network tab for 401/403 responses
  • Verify session cookie is being sent

Network Errors

Error: Possible CORS or Service Down error Solution:
  • Check backend server is running
  • Verify URL configuration
  • Test endpoint with curl

Next Steps

Configuration

Learn about environment and deployment configuration

Project Structure

Review the project file organization

Build docs developers (and LLMs) love