Home > database >  How to use the JSON response from a Python App, To render it with Javascript on to an HTML page usin
How to use the JSON response from a Python App, To render it with Javascript on to an HTML page usin

Time:02-22

  1. 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})
    

Rendered HTML

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">
  1. It works like I'd need it to - it posts the data to my Python calculator app which sends a JSON request back:

Output from Py App

  1. 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);
    

From locally saved JSON file

  1. 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>
  • Related