I have an HTML page being rendered with FastAPI:
@app.get("/index", response_class=HTMLResponse) def write_home(request: Request): return templates.TemplateResponse("index.html", {"request": request})
Above HTML has a Submit btn for a Form clicking which will result in a POST request the endpoint \SWP
<form id="generate" action="swp" method="post" enctype="multipart/form-data">
- It works like I'd need it to - it posts the data to my Python calculator app which sends a JSON request back:
With a JSON file saved locally on the hard drive, I was able to code JavaScript which could read its data and create a Chart via Chart.js. I used FetchAPI and then used the object array:
const API_URL = "./Example_Response.json"; async function createChartAndTable() { let ResponseFromAPI = await fetch(API_URL); let JSON_Res = await ResponseFromAPI.json(); let JSON_Data1 = JSON.parse(JSON_Res.output.data);
- Now, Im completely puzzled as to how Im to use the Live JSON result from the Python app http://127.0.0.1:8000/swp (Step2) and then render it to the HTML generated in Step 1 to http://127.0.0.1:8000/index like I was able to with the locally stored JSON file as in Step 3.
Note: theres no database involved.
Any guidance and help is much appreciated.
CodePudding user response:
Got it to work with the below code. The trick like @The Fool suggested in one of his/her comments
document.forms['myFormId'].addEventListener('submit', (event) => {
event.preventDefault();
// TODO do something here to show user that form is being submitted
fetch(event.target.action, {
method: 'POST',
body: new URLSearchParams(new FormData(event.target)) // event.target is the form
}).then((resp) => {
return resp.json(); // or resp.text() or whatever the server sends
}).then((body) => {
// TODO handle body
}).catch((error) => {
// TODO handle error
});
});
What I did was place my already written JS code within "Todo handle body". That worked!
CodePudding user response:
Option 1 would be to post the request through HTML
form and then have the API redirect you to a new page (Jinja template), where you can read the data and display the chart. As @tiangolo posted here, when performing a RedirectResponse
from a POST
request route to GET
request route, the response status code has to change to status_code=status.HTTP_303_SEE_OTHER
(the example below does that).
Option 2 would be to use Fetch API
to post the request, receive the JSON
data and display the chart on the same page.
Both options are demonstrated in the example given below (the data used is sample data for the purposes of this demo; you can change/handle them as required).
app.py
from fastapi import FastAPI, Request, status, Form
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.responses import RedirectResponse
app = FastAPI()
templates = Jinja2Templates(directory="templates")
json_data = {"jsonarray": [{"name": "Joe", "age": 32}, {"name": "Tom", "age": 34}]}
@app.get("/chart", response_class=HTMLResponse)
def get_chart(request: Request):
return templates.TemplateResponse("chart.html", {"request": request, "json_data": json_data})
@app.post("/submitUsingFetch")
def submitUsingFetch(request: Request, input1: str = Form(...), input2: str = Form(...)):
return json_data
@app.post("/submitUsingForm", response_class=HTMLResponse)
def submitUsingForm(request: Request, input1: str = Form(...), input2: str = Form(...)):
redirect_url = request.url_for('get_chart')
return RedirectResponse(redirect_url, status_code=status.HTTP_303_SEE_OTHER)
@app.get("/", response_class=HTMLResponse)
def home(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
templates/index.html
<!DOCTYPE html>
<html>
<head>
<title> Home</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script>
function send_request() {
const formElems = document.getElementById('my_form');
var formData = new FormData(formElems);
const url = "http://127.0.0.1:8000/submitUsingFetch";
fetch(url, {
method: 'POST',
headers: {'Accept': 'application/json'},
body: formData
}).then((resp) => {
return resp.json();
}).then((body) => {
display_chart(body)
}).catch((error) => {
console.log(error);
});
}
function display_chart(json_data) {
var labels = json_data.jsonarray.map(function(e) {return e.name;});
var data = json_data.jsonarray.map(function(e) {return e.age;});
var ctx = canvas.getContext('2d');
var config = {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Graph Line',
data: data,
backgroundColor: 'rgba(0, 119, 204, 0.3)'
}]
}
};
var chart = new Chart(ctx, config);
}
</script>
</head>
<body>
<form action="/submitUsingForm" method='post' id='my_form' enctype="multipart/form-data">
<label>Input 1:</label><br>
<input type="text" id="input1" name="input1" value="0"><br>
<label>Input 2:</label><br>
<input type="text" id="input2" name="input2" value="0"><br>
<input type="submit" value="Submit using Form">
<input type="button" value="Submit using Fetch" onclick="send_request()">
</form>
<canvas id="canvas"></canvas>
</body>
</html>
templates/chart.html
<html>
<head>
<head>
<title> Chart</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script>
function display_chart(){
var json_data = {{json_data|tojson}};
var labels = json_data.jsonarray.map(function(e) {return e.name;});
var data = json_data.jsonarray.map(function(e) {return e.age;});
var ctx = canvas.getContext('2d');
var config = {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Graph Line',
data: data,
backgroundColor: 'rgba(0, 119, 204, 0.3)'
}]
}
};
var chart = new Chart(ctx, config);
}
</script>
</head>
<body onl oad="display_chart()">
<canvas id="canvas"></canvas>
</body>
</html>