# API

This document describes the demonstration REST API implemented in `api_server.py` and `api_client.py`.

The API exposes the DQN path planner through a small Flask server. It allows an external client to set a geodetic start and goal position, generate a path using the trained DQN planner, and retrieve the resulting mission path as text.

## Overview

The API provides a lightweight interface around the `PathPlanner` class.

The server:

- creates a Flask application
- initializes a `PathPlanner`
- accepts start and goal coordinates through a query string
- updates the planner's mission start and goal
- generates a mission path
- returns the generated mission path as plain text

The client:

- sends start and goal coordinates to the server
- requests the generated path
- prints the returned mission text

The generated path is returned in the same mission format produced by `PathPlanner`: an ArduPilot/QGroundControl-compatible waypoint text format beginning with:

```text
QGC WPL 110
```

## Files

| File | Description |
|---|---|
| `api_server.py` | Flask server exposing the path planner through HTTP endpoints |
| `api_client.py` | Simple client script demonstrating how to call the API |

## API Server

The API server creates a Flask app and initializes a `PathPlanner` instance.

```python
app = Flask(__name__)
planner = PathPlanner()
```

The planner instance is reused across requests.

## Endpoints

## `GET /assign-start-goal`

Sets the geodetic start and goal coordinates used by the planner.

### Query Parameters

| Parameter | Format | Description |
|---|---|---|
| `start` | `lat_lon_alt` | Geodetic start position |
| `goal` | `lat_lon_alt` | Geodetic goal position |

Example request:

```text
/assign-start-goal?start=42.355118_-71.071305_6&goal=42.355280_-71.070911_26.5
```

The endpoint parses the start and goal values, converts them to floats, and passes them to the planner:

```python
planner.set_start(*start)
planner.set_goal(*goal)
```

### Response

If the start and goal are successfully set, the endpoint returns an empty response with status code:

```text
200 OK
```

If no start or goal is provided, the endpoint returns an example URL pattern using the planner's current default coordinates.

## `GET /get-path`

Generates and returns a mission path.

Example request:

```text
/get-path
```

The endpoint calls:

```python
path = planner.run()
```

and returns the generated mission path as plain text.

### Response

Successful response:

```text
201 Created
```

Response body:

```text
QGC WPL 110
0    0    0    22    ...
1    0    3    82    ...
...
```

The returned content is the generated mission path, not JSON.

## Running the API Demo

Open two terminals from the project root.

If using a virtual environment, activate it in both terminals.

## Terminal 1: Start the API Server

```bash
python -m dqn_path_planning.api_server
```

Or, if running the file directly from the source folder:

```bash
python api_server.py
```

Expected Flask development-server output will look similar to:

```text
 * Serving Flask app 'api_server'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
```

The default local API address is:

```text
http://127.0.0.1:5000
```

## Terminal 2: Run the API Client

In a second terminal, run:

```bash
python -m dqn_path_planning.api_client
```

Or, if running the file directly from the source folder:

```bash
python api_client.py
```

The client sends the default start and goal coordinates to the server, requests a path, and prints the returned mission text.

## Custom Start and Goal

The client supports custom start and goal coordinates using underscore-separated values.

```bash
python -m dqn_path_planning.api_client \
    --start 42.355118_-71.071305_6 \
    --goal 42.355280_-71.070911_26.5
```

The coordinate format is:

```text
latitude_longitude_altitude
```

For example:

```text
42.355118_-71.071305_6
```

represents:

```text
latitude = 42.355118
longitude = -71.071305
altitude = 6
```

## Client Workflow

The client performs two requests.

First, it sends the start and goal positions:

```python
set_start_and_goal(opt.start, opt.goal)
```

This calls:

```text
GET /assign-start-goal
```

Then it requests the generated path:

```python
path_content = get_path_from_api()
```

This calls:

```text
GET /get-path
```

If the server returns status code `201`, the client prints the returned mission path.

## Example Client Output

The output is a generated waypoint mission file.

```text
QGC WPL 110
0    0    0    22    0    0    0    0    42.355118    -71.071305    6.0    1
1    0    3    82    0    0    0    0    42.355118    -71.071299    6.0    1
2    0    3    82    0    0    0    0    42.355118    -71.071293    6.0    1
```

The mission output follows the `QGC WPL 110` waypoint format used in ArduPilot/QGroundControl-compatible workflows.

## API Output Format

The `/get-path` endpoint returns plain text.

It does not currently return:

- JSON
- a file attachment
- a CSV response
- a raw action sequence
- a Cartesian path

Instead, it returns the generated mission path text directly.

This makes the API useful as a simple bridge between the trained path planner and an external robotics or simulation component that can consume the generated mission output.

## Notes

- This API is intended as a demonstration/development interface.
- The Flask development server should not be used as a production deployment server.
- The server keeps a single `PathPlanner` instance in memory.
- The start and goal should be assigned before requesting a path.
- The returned path is generated using the trained DQN policy.
- The API returns ArduPilot/QGroundControl-compatible mission text.
- The API is not ROS2-specific, but it can be used as a boundary between the DQN planner and a broader robotics integration layer.
- If the server URL changes, update the `base_url` value in `api_client.py`.