Fastapi problem with uploading image - file uploads only work with Swagger UI - jinja2

I am having problem uploading image to my Fastapi endpoint using a File input component.
I have my backend endpoint as follows:
#router.post("/create", response_class=HTMLResponse)
#login_required
def job_create_post_view(
request: Request,
db:Session=Depends(get_db),
job_title: str=Form(default=None),
job_image:Optional[UploadFile]=File(default=None)
):
And my jinja2 template with the file uploader input as follows:
<form method="post" action="/jobs/create" hx-post="/jobs/create">
<div>
<label for="job_image">Upload a photo </label>
<input class="form-control" type="file" id="job_image" name="job_image" accept=".jpeg,.png,.jpg" placeholder="image" value="{%if job_image%} {{job_image}} {%endif%}">
</div>
<button class="btn btn-primary mt-2" type="submit"> Submit </button>
</form>
However, after I post the form, the value of the job_image is not picked up in my backend (returns a default None value). For example if I do a print(job_image.filename) I get nothing.
Strangely when I post the form using Swagger UI at localhost:8000/docs it returns the job_image without any issues.
So it seems my input component in the Jinja2 template is faulty but I can't see anything wrong with it.
This must have something to do with Starlette as print(job_image) is giving me <starlette.datastructures.UploadFile object>
In my browser I am getting the following error:
Response Status Error Code 422 from /jobs/create htmx.org#1.6.1:1

Related

When submitting a form with POST method, 405 Error shows up

My project is to have a user input a name of an anime and it will call the Jikan API to give out a list of shows and also display the theme songs links with the Spotify API on a separate HTML file (search.html). However, when trying to submit the form, it will display the correct URL "{website}/search.html" but will give me a 405 error. I'm using glitch.me to help host my website so I am able to see that the search.html works, but only when I type out the URL not when submitting the form. When I use a GET request for the form, however, it will display the shows but the Spotify API will give an error ({"error":"invalid_grant","error_description":"Invalid authorization code"}). It will still display the links from Spotify, but Im worried about that error. I wondering whether it was because of the POST method or something with my code.
index.html
<form action="search.html" onsubmit="testJS()" method="POST" id="theFormID" class="input-wrapper">
<button name="search" class="fa fa-search"></button>
<input type="text" id="search" placeholder="Search for anime..." value="" minlength="3">
<div class="fa fa-times" onclick="document.getElementById('search').value = ''"></div>
</form>
If you need to see more of my code let me know!

How to add csrf to flask app without wtforms?

I have a simple web app,
And I want to add csrf protection. But I didn’t understand the csrf wrapper provided by Flask-WTF. I've already seen the docs. But still didn’t understand how it works.
My questions is:
(1) After wrapping the app, Do I need to handle it from the route? Or flask take care of that for me?
(2) If Not how to handle it myself? (Please provide an example).
Note: I Don't want to use wtf forms, I wanted to use custom tags for inputs.
app.py :
from flask import Flask, render_template
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
csrf = CSRFProtect(app)
#app.route('/', methods=['GET'])
def get_home():
"""Get home template"""
return render_template('home.html')
#app.route('/', methods=['POST'])
def post_home():
"""Handle posted data and do stuff"""
return
home.html (form):
<form action="#" method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
<input type="text" placeholder="Name">
<button type="submit">
Submit
</button>
</form>
By default, you don't need to worry about validating it yourself - you simply deal with the other fields of the POST request as normal. If you look at the function csrf_protect() within the init_app function of the CSRFProtect class here (lines 202-225, https://github.com/lepture/flask-wtf/blob/master/flask_wtf/csrf.py), you can view the things which will stop the protect() function being run before a given request.

Handling multipart form data with express JS-values from text field are empty in req.body

I have a project in which I am using a basic sign up page for a user to enter their details.
I am using express JS at the backend
In this, I am also asking them to upload a picture. But for the picture to be uploaded, I need to make the enctype of the form as multipart/form-data. The image gets uploaded, but the problem is that none of the other data is recorded.
This is the html:
<form action="/create" method="POST" class="profile" enctype="multipart/form-data">
<input type="file" name="profile_image" class="img_upload" /><br><br><br>
<div class="name_age" >
<input type="text" name="name" class="name" placeholder="Full name">
<b class="age"> Age </b>
<input type="date" name="age" class="age"/>
</div>
<input type="submit" name="submit" value="Update Profile" class="button"/>
</form>
And this is expressJS code for handling it:
app.post('/create',(req,res)=>{
var d = req.body
console.log(d)
upload(req,res,function(err){ //this is a multer function to store the image
if(err)
res.end(err)
else{
res.end('success')
}
})
})
The console.log(d) returns an empty object. Without multipart/form-data the image doesn't get uploaded,but the rest of the data gets recorded.
How do I solve this issue?
I actually tried this as well in my project some months ago and got a similar problem with busboy as well as multer. You can have a onclick event on the button where you can have a setTimeout of 3,4 seconds (the usual time it will take to upload the image and send response) and send the text fields in the body in the ajax request to your url /create. Or just ditch the post request using the <form> tag and just send the image as well as the text fields in the ajax request. Hope it helps

django reverse url hitting same url

I have a base URL file that includes all apps URL files, and what I am trying to do is on click of Generate PDF Button, I want to hit an APIView / view-function passing a variable along as parameter via get method without encoding.
HTML:
<form onsubmit="{% url 'api-product:invoice-pdf-get' %}?R={{ variable }}">
<input type="submit" value="Generate PDF">
</form>
Base URL
path('api/product/', include(('store.urls', 'store'), namespace='api-product')),
path('invoice/', InvoiceUrl.as_view(), name='print-invoice'),
App URL:
path('invoice-pdf-get/', invoice.InvoiceToPdf.as_view(), name='invoice-pdf-get'),
On Click URL Generated: (Which is current, except with parameter)
http://localhost:8000/invoice/?
Can't understand why am I getting the same URL though when I inspect the HTML I see the URL included there, but without localhost:8000.
There are several answers related to reverse URL on StackOverflow, none helped.Also I am not having any java script etc included, only bootstrap and a simple custom CSS. Have just a plain table.
If I just open the HTML from windows file directory, and click button I get:
http://localhost:63342/pos2all/templates/pogo-invoice.html?
UPDATED:
Now the parameter is not passed though still visible in HTML inspect, same way as above picture.
The API Looks Like:
class InvoiceToPdf(APIView):
"""
This API is used to get the Invoice and return pdf of invoice
using rest_framework Response and premission_classes
"""
permission_classes = (AllowAny,)
def get(self, request):
return Response("hi")
Use the form action attribute instead of onsubmit.
<form action="{% url 'api-product:invoice-pdf-get' %}">
The action attribute is the url you want to form to be submitted to. But the form will add the data from the inputs as query parameters when you submit a form with the GET method, so you can't have a query string in the action url.
To pass query parameters with a form submission, use form inputs. You can use hidden fields for data that the user is not supposed to edit.
<form action="{% url 'api-product:invoice-pdf-get' %}" >
<input type="hidden" name="R" value="{{ variable }}" />
<input type="submit" value="Generate PDF" />
</form>
The default method for form submission is GET, but you can add the method explicitly to make this more clear.
<form method="get" action="{% url 'api-product:invoice-pdf-get' %}">

HTML form request body empty - NodeJs

I was tring to create an API POST using Node.js and express. I was just trying to post some data using html form:
<form id="myform" action="http://localhost:4000/add" method="post" enctype="application/json">
<input type="text" name="name" id="name" />
<input type="submit" id="submit" />
</form>
The server would just receive the POST request and display the body into console.log.
router.post('/add', function (req, res){
console.log("request: "+JSON.stringify(req.body));
})
What is being received at the console is:
request: {}
Trying to post into the same api using Postman - raw, JSON(application/JSON), things work fine.
Can someone please tell me what is wrong with what I am doing?
Browsers do not support submitting HTML forms as application/json. Most browsers would probably ignore the value and send the form as the default enctype which is application/x-www-form-urlencoded. To parse that, you'd need to use an appropriate middleware. One such example is the body-parser module's urlencoded() middleware.
In action attribute you don't need to specific the host just specify path such as "/add".