Unable to send attachment with the email using reactjs - reactjs

I'm new to react, my objective is to send attachment with the email. For emailing purpose, we're using sendgrid and for uploading files or attachments we're sendgrid mail helper attachment in backend. But i couldn't able to upload file, i can send only email but i couldn't able to send email with attachment. I couldn't able to figure it out where i'm going wrong. I have been struggling from couple of weeks but couldn't figure out where i'm going wrong.
Here is the code:
fileChange = e => {
this.setState(
{ file: e.target.files[0], fileName: e.target.files[0].name },
() => {
console.log(
"File chosen --->",
this.state.file,
console.log("File name --->", this.state.fileName)
);
}
);
};
<Button.Content hidden>Choose a File</Button.Content>
</Button>
<input
type="file"
id="file"
hidden
onChange={this.fileChange}
/>
<Form.Input
fluid
label="File Chosen: "
placeholder="browse your file system"
readOnly
value={this.state.fileName}
/>
Can anyone help me in this query please?

you are passing file but you set wrong content-type.
headers: { 'Content-Type': 'application/json' }
Please use the following line instead above line
headers: {"Content-Type": "multipart/form-data"}

Related

Format to POST a file to the ImageKit server?

I've successfully built a React UI to select and upload N files. The key part of it is this:
<input type='file' accept='image/*' id='selectFiles' multiple onChange={handleFileChange} />
The selected files are stored in this state variable:
const [fileList, setFileList] = React.useState<FileList>();
I know they're correctly there because I iterate through them and show them in a preview DIV.
Following ImageKit's instructions, I successfully built an Auth endpoint which returns the auth credentials.
Then, within a useEffect I iterated through fileList to upload one photo at a time to the ImageKit server. But even trying just one file, I keep getting a 400 error informing me that the fileName parameter is missing. It definitely is not missing so I suspect that the problem lies with what I'm providing as the file parameter.
Here's the critical code (with some data obscured for privacy reasons) :
const uploadFile = async (file: File) => {
try {
const body = {
file: file,
publicKey: 'my_public_key',
signature: 'imageKit_signature',
expire: 'imageKit_expiry_value',
token: 'imageKit_token',
fileName: 'test123.jpg',
useUniqueFileName: false,
folder: userName,
overwriteFile: false,
};
const response = await axios.post('https://upload.imagekit.io/api/v1/files/upload', body);
console.log(response.status, response.data);
} catch (err) {
console.error(err);
}
};
Might anyone see what I'm doing wrong?
Robert
I solved the problem. If you're going to upload a file to ImageKit using their POST endpoint, you need to explicitly set the headers like this:
const response = await axios.post(
'https://upload.imagekit.io/api/v1/files/upload',
body,
{ headers: {'Content-Type': 'multipart/form-data'} }
);
For those wondering, here's the barebones body:
const body = {
file: base64File,
publicKey: imageKitPublicKey,
signature: authParams?.signature,
expire: authParams?.expire,
token: authParams?.token,
fileName: 'someFilename.ext',
};
But indeed, specifying Content-Type like above will allow you to upload a file to their server.

Which HTTP Method to Use with Forms?

My web app information:
Frontend: React.js
Backend: Flask
Goal: User enters in zip codes and the backend returns the zip code coordinates and distance on the web page
Problem: I was initially under the impression that you only use POST requests when inserting into a database, so I was defining my API endpoints as GET methods. However, since I am under the assumption that it is best to not pass body parameters for GET methods, my current solution is to have it as a POST request. Is this the best practice? Or is there a better way to do it?
Frontend Code
const handleSubmit = e => {
const formData = { "origin": originInput, "destination": destinationInput
}
e.preventDefault();
checkError();
fetch('/path', {
credentials: 'include',
method: 'POST',
body: JSON.stringify(formData),
headers: { 'content-type': 'application/json' }
}).then(res => console.log(res))
.catch(err => console.log(err));
};
return (
<div className="card">
<form onSubmit={handleSubmit}>
<section>
<label htmlFor="origin">Start Zip</label>
<input
type="text"
name="origin"
id="origin"
onChange={e => handleChange(e, updateOriginInput)}
/>
</section>
<section>
<label htmlFor="destination">End Zip</label>
<input
type="text"
name="destination"
id="destination"
onChange={e => handleChange(e, updateDestinationInput)}
/>
</section>
<section>
<input type="submit" value="Get Directions" />
</section>
</form>
</div>
);
Backend Code
#path.route('/path', methods=['POST'])
def path_info():
request_data = request.get_json()
ORIGIN = request_data['origin']
DESTINATION = request_data['destination']
# The df var is pd.DataFrame(zip([ORIGIN, get_lon(ORIGIN), get_lat(ORIGIN)], [DESTINATION, get_lon(DESTINATION), get_lat(DESTINATION)])).T
df, MILES = preprocess(ORIGIN, DESTINATION)
print(df)
return {
'origin': {
'longitude': df['LON'][0],
'latitude': df['LAT'][0]
},
'destination': {
'longitude': df['LON'][1],
'latitude': df['LAT'][1]
},
'miles': MILES
}
Thanks in advance!
I was initially under the impression that you only use POST requests when inserting into a database, so I was defining my API endpoints as GET methods. However, since I am under the assumption that it is best to not pass body parameters for GET methods, my current solution is to have it as a POST request. Is this the best practice? Or is there a better way to do it?
Today: if you need to send information in the body of the HTTP request, then you should expect to use POST (with PUT/PATCH available in specific cases).
If you want to instead use GET, then you need to take the information collected by the form and figure out how to encode it into the request URI itself. On the web, that usually takes the form of key value pairs that have been application/x-www-form-urlcoded and copied into the query part of the request URI. It doesn't have to be in the query part - URI Templates can be used to describe the expansion of URI paths as well.
There is an internet draft to standardize a new HTTP method (QUERY) which would provide semantics for a safe request with a message body; but that method hasn't been standardized or registered yet.

Can't get file from POST request using Flask and Bootstrap-Vue Form File Input

I'm trying to upload and image using Bootstrap-Vue Form File Input and send it to Flask Backend via POST using Axios library, then store in a folder.
My problem is that Flask can't find "file" in "request.files". Pretty sure I'm falling in a rookie mistake.
That's my code:
Frontend:
<template>
<div class="mx-5 container-fluid">
<div class="mx-5 row">
<div class="col-sm-10">
<b-form-file
type="file"
id="file"
v-model="file"
:state="Boolean(file)"
ref="file"
placeholder="Choose a file or drop it here..."
drop-placeholder="Drop file here..."
v-on:change="submitFile"
></b-form-file>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
file: null,
};
},
methods: {
submitFile() {
/* Initialize the form data */
const path = 'http://localhost:5000/single-file';
const formData = new FormData();
/* Add the form data we need to submit */
formData.append('file', this.file);
/* Make the request to the POST /single-file URL */
axios.post(path,
formData,
{
headers: {
'Content-Type': 'multipart/form-data',
},
}).then(() => {
// console.log('SUCCESS!!');
})
.catch(() => {
// console.log('FAILURE!!');
});
},
},
};
Backend:
from flask import Flask, jsonify, request, send_file, redirect, url_for
from werkzeug.utils import secure_filename
import os
# configuration
DEBUG = True
UPLOAD_FOLDER = '/images'
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
#app.route('/single-file', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
print('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
print('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('download_file', name=filename))
return ''
if __name__ == '__main__':
app.run()
I get HTTP code 302 (redirect) and print in console 'No file part'.
Any help would be very apreciated.
I can't see an obvious mistake in your code, it seems that the request is correctly passed through from your frontend and backend.
What I would suggest is to use Postman to decouple your frontend and backend in this case. If you get a correct response when using Postman, you can narrow down that the error is in the frontend, the browser, or something about axios which is meddling with the request data.
Also, try to get an error message, or print why flask thinks "file" isnt in request.files, it should be there if everything works as intended
I followed the response for Get the data received in a Flask request to get to the flask documentation for the Request class: Each key in files is the name from the <input type="file" name="">, which means that most likely you have to change 'file' from file = request.files['file'] to point to the actual filename that was selected from the file selection menu.

How to upload a file using Gin + React?

I want to upload a image file from React, doing so seems I need to store the image on the server and retrieve it from a POST request in order to modify it into a url path.
Using Gin Gonic http framework.
Here is the form in React for my POST request:
<form action="/upload" method="POST">
<label htmlFor="upload" onChange={onChange}>
<FontAwesomeIcon icon={faUserCircle} color="#3B5998" size="10x" className={`${pointer}`} />
<input type="file" hidden id="upload" name="upload" />
</label>
</form>
Here is my method I am calling in an onChange to send the request along with the image file:
uploadFile = (file) => {
const formData = new FormData();
formData.append('image', file);
axios({
method: 'post',
url: `${gamingApiBaseURL}/v1/upload-image`,
data: formData,
headers: { 'Content-Type': 'multipart/form-data' },
}).catch((error) => {
console.log('error storing image', error);
});
};
Here is my Go struct in order to bind the request
type ImageForm struct {
Image *multipart.FileHeader `form:"upload binding:"required"`
}
Lastly, the method that is supposed to get the image file and upload it to the server. Here is what I have so far. I am receiving an error saying http: no such file which is weird because in Postman I see the image key and the filename, I'm trying to make sense of how uploading an image works in Go.
func extractImage(c *gin.Context) {
// Using 'ShouldBind'
formFile, err := c.FormFile("image")
fmt.Println("Error", err)
if err != nil {
c.JSON(http.StatusBadRequest, err)
}
fmt.Println("form error", formFile)
}
I think this struct tag is wrong
type ImageForm struct {
Image *multipart.FileHeader `form:"upload binding:"required"`
}
Change to this (missing double quote after upload):
type ImageForm struct {
Image *multipart.FileHeader `form:"upload" binding:"required"`
}

How to Save Image in server

I am trying to save an image in database but when I do the following it saves with dataURL, but that URL starts with localhost, how can I prevent it? I used React for frontend.
uploadImage = (event) => {
var imgSize = event.target.files[0].size;
$('#img').attr('hidden', false);
if (imgSize < 1000000 ) {
this.setState({
image: URL.createObjectURL(event.target.files[0]),
imageSize: imgSize
});
document.getElementById("errImgUpload").innerHTML = "";
}
else {
document.getElementById("errImgUpload").innerHTML = "Maximum image size 1Mb";
}
}
<div className="form-group">
<label for="file-upload" className="custom-file-upload">
<span className="fa fa-upload"></span> Upload image
</label>
<input onChange={(event) => this.uploadImage(event)} name="file-upload" id="file-upload" type="file" accept="image/*" />
<span id="errImgUpload" className="text text-danger"></span>
</div>
The Blob is http://localhost:10002/b46e96f5-83ce-4d10-b668-2bd038721b5a, what is a blob?
URL.createObjectURL() creates a blob which is a binary representation of the file in the memory. It doesn't upload the file. I am not sure from where you got the code. You may want to read more about this at MDN.
Uploading requires a backend service to open an endpoint for you to send post data to. You need to use <input type='file'> tag to send the file as form data and set the service endpoint as the url in the form. Start with this article.
You need to post your image data with FormData, like this:
const formData = new FormData();
formData.append('image', files[0]);
fetch(url, {
method: 'POST',
body: data
}).then(...);
And blob is Binary Large Object, more detail you can find in MDN.

Resources