added frontend and script examples
This commit is contained in:
parent
368c4de6fe
commit
61b10a2bc2
6 changed files with 385 additions and 0 deletions
53
README.md
53
README.md
|
@ -101,6 +101,59 @@ Response:
|
||||||
- CSV files: Must have a header row with column names
|
- CSV files: Must have a header row with column names
|
||||||
- JSON files: Must contain valid JSON data
|
- JSON files: Must contain valid JSON data
|
||||||
|
|
||||||
|
## Using the API in External Applications
|
||||||
|
|
||||||
|
### Python Example
|
||||||
|
|
||||||
|
Here's how to consume the API data in a Python script:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
import pandas as pd
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
# Base URL of the API
|
||||||
|
API_BASE_URL = 'http://localhost:8000'
|
||||||
|
|
||||||
|
# Example 1: Get users data
|
||||||
|
response = requests.get(f"{API_BASE_URL}/api/users")
|
||||||
|
users_data = response.json()
|
||||||
|
pprint(users_data)
|
||||||
|
|
||||||
|
# Example 2: Get contacts and convert to DataFrame
|
||||||
|
response = requests.get(f"{API_BASE_URL}/api/contacts")
|
||||||
|
contacts_data = response.json()
|
||||||
|
contacts_df = pd.DataFrame(contacts_data)
|
||||||
|
print(contacts_df)
|
||||||
|
|
||||||
|
# Example 3: Extract specific information
|
||||||
|
contacts_response = requests.get(f"{API_BASE_URL}/api/contacts")
|
||||||
|
contacts = contacts_response.json()
|
||||||
|
locations = [contact['location'] for contact in contacts]
|
||||||
|
print(f"Available locations: {locations}")
|
||||||
|
|
||||||
|
# Example 4: Filtering data
|
||||||
|
users_response = requests.get(f"{API_BASE_URL}/api/users")
|
||||||
|
users_data = users_response.json()
|
||||||
|
filtered_users = [user for user in users_data.get('users', [])
|
||||||
|
if user.get('name') == 'John']
|
||||||
|
print(f"Filtered users: {filtered_users}")
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
```
|
||||||
|
{'users': [{'name': 'John', 'email': 'john@example.com'},
|
||||||
|
{'name': 'Jane', 'email': 'jane@example.com'}]}
|
||||||
|
|
||||||
|
location contact
|
||||||
|
0 dortmund achim
|
||||||
|
1 madrid santos
|
||||||
|
|
||||||
|
Available locations: ['dortmund', 'madrid']
|
||||||
|
|
||||||
|
Filtered users: [{'name': 'John', 'email': 'john@example.com'}]
|
||||||
|
```
|
||||||
|
|
||||||
## Manual Container Setup
|
## Manual Container Setup
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
33
frontend/README.md
Normal file
33
frontend/README.md
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Static2API Frontend
|
||||||
|
|
||||||
|
This is a simple frontend that displays data from the Static2API application. It's designed to work with the API without requiring any changes to the container or backend.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Start the Static2API application either directly or via container:
|
||||||
|
```
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```
|
||||||
|
./run_container.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Open the `index.html` file in your browser:
|
||||||
|
- You can use any static file server
|
||||||
|
- Or simply open the file directly in your browser
|
||||||
|
|
||||||
|
3. The frontend will fetch data from the following endpoints:
|
||||||
|
- `/` - Root endpoint
|
||||||
|
- `/api/users` - Users data
|
||||||
|
- `/api/contacts` - Contacts data
|
||||||
|
|
||||||
|
## CORS Support
|
||||||
|
|
||||||
|
The FastAPI application has been updated with CORS middleware to allow cross-origin requests from this frontend. This means you can:
|
||||||
|
|
||||||
|
1. Open the HTML file directly in your browser
|
||||||
|
2. Access the API endpoints without CORS restrictions
|
||||||
|
3. Serve the frontend from any static file server
|
||||||
|
|
||||||
|
No additional configuration is needed for CORS support.
|
110
frontend/index.html
Normal file
110
frontend/index.html
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Static2API Frontend</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.endpoints {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.endpoint {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 300px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
.endpoint h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #2c3e50;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.example {
|
||||||
|
margin-top: 40px;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f0f8ff;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-left: 4px solid #4a90e2;
|
||||||
|
}
|
||||||
|
.example h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #2c3e50;
|
||||||
|
}
|
||||||
|
.location-list {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.location-item {
|
||||||
|
background-color: #e8f4fd;
|
||||||
|
padding: 8px 15px;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid #c8e1fb;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Static2API Frontend</h1>
|
||||||
|
<div class="endpoints">
|
||||||
|
<div class="endpoint">
|
||||||
|
<h2>Root Endpoint</h2>
|
||||||
|
<div id="root-data" class="loading">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="endpoint">
|
||||||
|
<h2>Users API</h2>
|
||||||
|
<div id="users-data" class="loading">Loading...</div>
|
||||||
|
</div>
|
||||||
|
<div class="endpoint">
|
||||||
|
<h2>Contacts API</h2>
|
||||||
|
<div id="contacts-data" class="loading">Loading...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="example">
|
||||||
|
<h2>Example: Locations from Contacts</h2>
|
||||||
|
<p>This example extracts and displays all unique locations from the contacts data:</p>
|
||||||
|
<div id="locations-example" class="loading">Loading locations...</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
88
frontend/script.js
Normal file
88
frontend/script.js
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// Set the base URL for the API
|
||||||
|
// When running locally without the container, you would use:
|
||||||
|
const API_BASE_URL = 'http://localhost:8000';
|
||||||
|
|
||||||
|
// When accessing the API running in a container, you would use:
|
||||||
|
// const API_BASE_URL = 'http://localhost:8000';
|
||||||
|
// Adjust the port if needed according to your container setup
|
||||||
|
|
||||||
|
// Function to fetch data from the API and update the UI
|
||||||
|
async function fetchEndpoint(endpoint, elementId) {
|
||||||
|
const dataElement = document.getElementById(elementId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}${endpoint}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
// Create a formatted JSON string with syntax highlighting
|
||||||
|
const formattedJson = JSON.stringify(data, null, 2);
|
||||||
|
|
||||||
|
// Update the UI with the fetched data
|
||||||
|
dataElement.innerHTML = `<pre>${formattedJson}</pre>`;
|
||||||
|
|
||||||
|
return data; // Return the data for potential further processing
|
||||||
|
} catch (error) {
|
||||||
|
dataElement.innerHTML = `<div class="error">Error: ${error.message}</div>`;
|
||||||
|
console.error(`Failed to fetch ${endpoint}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch data from all endpoints
|
||||||
|
fetchEndpoint('/', 'root-data');
|
||||||
|
fetchEndpoint('/api/users', 'users-data');
|
||||||
|
|
||||||
|
// Fetch contacts data and then process it to display locations
|
||||||
|
fetchEndpoint('/api/contacts', 'contacts-data')
|
||||||
|
.then(contactsData => {
|
||||||
|
if (contactsData) {
|
||||||
|
// Process the contacts data to extract unique locations
|
||||||
|
displayLocationsExample(contactsData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Function to display the locations example
|
||||||
|
function displayLocationsExample(contactsData) {
|
||||||
|
const locationsElement = document.getElementById('locations-example');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Extract all unique locations from the contacts data
|
||||||
|
const locations = [...new Set(contactsData.map(contact => contact.location))];
|
||||||
|
|
||||||
|
if (locations.length === 0) {
|
||||||
|
locationsElement.innerHTML = '<p>No locations found in the contacts data.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create HTML for the locations list
|
||||||
|
const locationsHTML = `
|
||||||
|
<p>Found ${locations.length} unique location(s):</p>
|
||||||
|
<ul class="location-list">
|
||||||
|
${locations.map(location => `
|
||||||
|
<li class="location-item">${location}</li>
|
||||||
|
`).join('')}
|
||||||
|
</ul>
|
||||||
|
<p>Code example:</p>
|
||||||
|
<pre>
|
||||||
|
// JavaScript to extract unique locations
|
||||||
|
const locations = [...new Set(
|
||||||
|
contactsData.map(contact => contact.location)
|
||||||
|
)];
|
||||||
|
|
||||||
|
console.log(locations); // ${JSON.stringify(locations)}
|
||||||
|
</pre>
|
||||||
|
`;
|
||||||
|
|
||||||
|
locationsElement.innerHTML = locationsHTML;
|
||||||
|
} catch (error) {
|
||||||
|
locationsElement.innerHTML = `<div class="error">Error processing locations: ${error.message}</div>`;
|
||||||
|
console.error('Error processing locations:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
10
main.py
10
main.py
|
@ -1,5 +1,6 @@
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
import json
|
import json
|
||||||
|
@ -7,6 +8,15 @@ from pathlib import Path
|
||||||
|
|
||||||
app = FastAPI(title="Static2API")
|
app = FastAPI(title="Static2API")
|
||||||
|
|
||||||
|
# Add CORS middleware to allow cross-origin requests
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["*"], # Allows all origins
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"], # Allows all methods
|
||||||
|
allow_headers=["*"], # Allows all headers
|
||||||
|
)
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
return {"message": "Welcome to Static2API"}
|
return {"message": "Welcome to Static2API"}
|
||||||
|
|
91
scripts/access_devices.sh
Executable file
91
scripts/access_devices.sh
Executable file
|
@ -0,0 +1,91 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
API_URL="http://localhost:8000/api/devices"
|
||||||
|
|
||||||
|
# Create a logs directory for output files
|
||||||
|
LOGS_DIR="./device_logs"
|
||||||
|
mkdir -p $LOGS_DIR
|
||||||
|
|
||||||
|
# Function to check if a command exists
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if curl or wget is available
|
||||||
|
if command_exists curl; then
|
||||||
|
echo "Using curl to fetch data..."
|
||||||
|
RESPONSE=$(curl -s $API_URL)
|
||||||
|
elif command_exists wget; then
|
||||||
|
echo "Using wget to fetch data..."
|
||||||
|
RESPONSE=$(wget -qO- $API_URL)
|
||||||
|
else
|
||||||
|
echo "Error: Neither curl nor wget is available. Please install one of them."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if response is empty
|
||||||
|
if [ -z "$RESPONSE" ]; then
|
||||||
|
echo "Error: Received empty response from $API_URL"
|
||||||
|
echo "Make sure the API server is running and the /api/devices endpoint exists."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if jq is available for JSON parsing
|
||||||
|
if command_exists jq; then
|
||||||
|
echo "Using jq to parse JSON..."
|
||||||
|
|
||||||
|
# Extract devices using jq
|
||||||
|
# This is flexible to handle different JSON structures
|
||||||
|
|
||||||
|
# Try to parse top-level array first
|
||||||
|
DEVICE_COUNT=$(echo $RESPONSE | jq '. | length' 2>/dev/null)
|
||||||
|
|
||||||
|
# If not an array or empty, try .devices field (common pattern)
|
||||||
|
if [ -z "$DEVICE_COUNT" ] || [ "$DEVICE_COUNT" = "0" ]; then
|
||||||
|
DEVICE_COUNT=$(echo $RESPONSE | jq '.devices | length' 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -n "$DEVICE_COUNT" ] && [ "$DEVICE_COUNT" -gt 0 ]; then
|
||||||
|
echo "Found $DEVICE_COUNT devices in .devices field"
|
||||||
|
echo "-------------------------------------"
|
||||||
|
|
||||||
|
for i in $(seq 0 $(($DEVICE_COUNT-1))); do
|
||||||
|
NAME=$(echo $RESPONSE | jq -r ".devices[$i].name // .devices[$i].hostname // .devices[$i].device // \"Unknown\"")
|
||||||
|
IP=$(echo $RESPONSE | jq -r ".devices[$i].ip // .devices[$i].ipaddress // .devices[$i].ip_address // \"Unknown\"")
|
||||||
|
TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
|
echo "Connecting to $NAME ($IP) at $TIME"
|
||||||
|
ssh user@$IP "get vpn ssl monitor" > "$LOGS_DIR/${NAME}_${TIME}.log"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "No devices found or unexpected JSON structure."
|
||||||
|
echo "Raw API response:"
|
||||||
|
echo "$RESPONSE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Found $DEVICE_COUNT devices in top-level array"
|
||||||
|
echo "-------------------------------------"
|
||||||
|
|
||||||
|
for i in $(seq 0 $(($DEVICE_COUNT-1))); do
|
||||||
|
NAME=$(echo $RESPONSE | jq -r ".[$i].name // .[$i].hostname // .[$i].device // \"Unknown\"")
|
||||||
|
IP=$(echo $RESPONSE | jq -r ".[$i].ip // .[$i].ipaddress // .[$i].ip_address // \"Unknown\"")
|
||||||
|
TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
|
echo "Connecting to $NAME ($IP) at $TIME"
|
||||||
|
ssh user@$IP "get vpn ssl monitor" > "$LOGS_DIR/${NAME}_${TIME}.log"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Warning: jq is not available for proper JSON parsing. Using basic parsing..."
|
||||||
|
|
||||||
|
# Very basic parsing fallback without jq (limited)
|
||||||
|
# Extract name and IP with grep and sed - this is fragile but better than nothing
|
||||||
|
echo "$RESPONSE" | grep -o '"name"\s*:\s*"[^"]*"\|"ip"\s*:\s*"[^"]*"' | sed 's/"name"\s*:\s*"\([^"]*\)"/\1/g; s/"ip"\s*:\s*"\([^"]*\)"/\1/g' | paste -d " " - - | while read -r NAME IP; do
|
||||||
|
TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
echo "Connecting to $NAME ($IP) at $TIME"
|
||||||
|
ssh user@$IP "get vpn ssl monitor" > "$LOGS_DIR/${NAME}_${TIME}.log"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "-------------------------------------"
|
||||||
|
echo "Script completed. Log files saved to $LOGS_DIR directory."
|
Loading…
Add table
Add a link
Reference in a new issue