Skip to main content

Overview

The Solicitud Transporte API is a FastAPI-based backend system for managing transportation requests and missions for ONI Justicia. This guide will help you set up and run the API locally, and make your first API call.

Prerequisites

Before you begin, ensure you have the following installed:
  • Python 3.8 or higher
  • pip (Python package manager)
  • SQL Server (for the main database)
  • MongoDB (optional, for logging)
  • Git (for cloning the repository)

Installation

1

Clone the repository

Clone the Solicitud Transporte API repository to your local machine:
git clone https://github.com/pedro-navarrete/Solicitud_Transporte_Api_V2.git
cd Solicitud_Transporte_Api_V2
2

Install dependencies

Install the required Python packages using pip:
pip install -r requirements.txt
The main dependencies include:
  • fastapi - Modern web framework for building APIs
  • pymssql - SQL Server database driver
  • pydantic - Data validation using Python type annotations
  • python-dotenv - Environment variable management
  • requests - HTTP library for making API calls
  • jinja2 - Templating engine
3

Configure environment variables

Create a .env file in the root directory with the following configuration:
.env
# Application Settings
API_TITLE=Backend ONI Justicia
API_VERSION=1.0.0
API_DEBUG=true
API_LOG_LEVEL=INFO
API_LOG_FORMAT=text
TIMEZONE=America/El_Salvador

# SQL Server Configuration
SQL_HOST=localhost
SQL_PORT=1433
SQL_NAME=your_database_name
SQL_USER=your_username
SQL_PASSWORD=your_password

# MongoDB Configuration (Optional)
DB_URL=mongodb://localhost:27017/dev_oni_justicia
# OR use individual variables:
DB_HOST=localhost
DB_PORT=27017
DB_NAME=dev_oni_justicia
DB_USER=admin
DB_PASSWORD=your_mongodb_password
DB_AUTH_DB=admin

# JWT Configuration
JWT_SECRET=your-secret-key-here-change-in-production
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXP_VALUE=60
JWT_ACCESS_TOKEN_EXP_UNIT=minutes
JWT_REFRESH_TOKEN_EXP_VALUE=24
JWT_REFRESH_TOKEN_EXP_UNIT=hours

# API Credentials
API_USER=api_user
API_PASSWORD=your-secure-password

# Email Configuration (Optional)
EMAIL_USER=[email protected]
EMAIL_PASSWORD=your-email-password
EMAIL_SMTP_HOST=smtp.gmail.com
EMAIL_SMTP_PORT=587
EMAIL_USE_TLS=true

# MFA Configuration
MFA_ISSUER_NAME=ONI_Justicia
MFA_VALID_WINDOW=1
Make sure to change the JWT_SECRET and API_PASSWORD to secure values in production environments. Never commit your .env file to version control.
4

Start the server

Run the FastAPI application using uvicorn:
uvicorn main:app --reload --host 0.0.0.0 --port 8000
You should see output similar to:
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Started reloader process
INFO:     Started server process
INFO:     Waiting for application startup.
============================================================
🚀 Backend ONI Justicia v1.0.0 iniciando...
📋 Documentación: /docs | /redoc
🔧 Modo debug: True
📝 Nivel de log: INFO
============================================================
INFO:     Application startup complete.
The --reload flag enables auto-reload on code changes, which is useful for development.
5

Verify the installation

Open your browser and navigate to:The health check endpoint should return:
{
  "exito": true,
  "mensaje": "API funcionando correctamente",
  "datos": {
    "servicio": "Backend ONI Justicia",
    "version": "1.0.0"
  }
}

Making Your First API Call

Now that your API is running, let’s make your first request to list transport request statuses.

Using cURL

curl -X GET "http://localhost:8000/estado-solicitud/" \
  -H "accept: application/json"

Using Python

import requests

response = requests.get("http://localhost:8000/estado-solicitud/")
data = response.json()

if data["exito"]:
    print("Request statuses:")
    for estado in data["datos"]:
        print(f"- {estado['nombre']} ({estado['codigo']})")
else:
    print(f"Error: {data['mensaje']}")

Using JavaScript

fetch('http://localhost:8000/estado-solicitud/')
  .then(response => response.json())
  .then(data => {
    if (data.exito) {
      console.log('Request statuses:', data.datos);
    } else {
      console.error('Error:', data.mensaje);
    }
  });

Expected Response

{
  "exito": true,
  "mensaje": "Listado de estados de solicitud obtenido exitosamente",
  "datos": [
    {
      "idEstadoSolicitud": 1,
      "nombre": "Pendiente de Aprobación",
      "codigo": "PENDIENTE_APROBACION",
      "color": "#FFA500",
      "descripcion": "Solicitud creada y en espera de aprobación",
      "esActivo": true
    },
    {
      "idEstadoSolicitud": 2,
      "nombre": "Aprobada",
      "codigo": "APROBADA",
      "color": "#00FF00",
      "descripcion": "Solicitud aprobada por el supervisor",
      "esActivo": true
    }
  ]
}

Creating a Transport Request

Let’s create a complete transport request with multiple destinations:
curl -X POST "http://localhost:8000/solicitud/" \
  -H "Content-Type: application/json" \
  -d '{
    "idUsuarioSolicitante": 1,
    "idDepartamentoSolicitante": 2,
    "idUsuarioAprobador": 3,
    "idTipoPrioridadSolicitud": 2,
    "idTipoServicioSolicitud": 1,
    "asunto": "Transporte de personal a sede central",
    "descripcion": "Se requiere transporte para personal de la unidad",
    "justificacion": "Reunión de coordinación institucional",
    "cantidadPasajeros": 5,
    "nombresPasajeros": "Juan Pérez, María López, Carlos Rivas",
    "fechaServicioRequerido": "2026-04-15",
    "horaServicioRequerido": "08:00",
    "observaciones": "Llevar a las 8am y regresar a las 5pm",
    "lugares": [
      {
        "idLugar": 5,
        "esOrigen": true,
        "orden": 0,
        "descripcion": "Sede central - Salida"
      },
      {
        "idLugar": 12,
        "esOrigen": false,
        "orden": 1,
        "descripcion": "Primer destino",
        "horaEstimadaLlegada": "10:30",
        "requiereRetorno": true,
        "horaEstimadaRetorno": "12:00"
      }
    ]
  }'
When a request is created, it automatically enters the PENDIENTE_APROBACION (Pending Approval) state. The system generates a unique code in the format SOL-{YEAR}-{MONTH}-{CORRELATIVE}.

Understanding the Response Format

All API responses follow a consistent structure:
{
  "exito": true,
  "mensaje": "Operation success message",
  "datos": {
    // Response data here
  }
}

Success Response

  • exito: true - Indicates the operation was successful
  • mensaje: Description of the operation result
  • datos: The actual response data (object or array)

Error Response

{
  "exito": false,
  "mensaje": "Error description",
  "detalle": "Additional error details"
}

Common HTTP Status Codes

Status CodeMeaningExample
200SuccessData retrieved successfully
201CreatedNew resource created
400Bad RequestInvalid input data
404Not FoundResource doesn’t exist
409ConflictOperation conflicts with current state
422Validation ErrorInput validation failed
500Internal ErrorServer-side error

Next Steps

Now that you have the API running, explore these resources:

Authentication

Learn how to secure your API requests with JWT authentication

API Reference

Explore all available endpoints and their parameters

Request Lifecycle

Understand the complete workflow from request to completion

Error Handling

Learn about error handling and validation

Troubleshooting

If you’re experiencing database connection issues:
  1. Verify your SQL Server is running
  2. Check that the credentials in .env are correct
  3. Ensure the database exists
  4. Test connection using SQL Server Management Studio
  5. Check firewall rules allow connections on port 1433
If you see ModuleNotFoundError:
pip install -r requirements.txt --upgrade
Make sure you’re using Python 3.8 or higher:
python --version
If port 8000 is already in use, specify a different port:
uvicorn main:app --reload --port 8001
If you see warnings about missing JWT_SECRET:
# Generate a secure random key
python -c "import secrets; print(secrets.token_urlsafe(32))"
Add the output to your .env file as JWT_SECRET.
For additional help, check the logs in the console output or review the Error Handling guide.

Build docs developers (and LLMs) love