Failing to send image to Go server - javascript

Recently I started working with Go to make servers, in my current experiment I am trying to upload an image to my Go/mux webserver via fetch on a React.js front-end. Whenever I upload an image through a form the server fails to receive the image and returns a "no such file" error. I am using JS's FormData API to store and send the image.
Here is the code for the client
handleInput = (e) => {
let formData = new FormData();
formData.append("myImage", e.target.files)
fetch("http://localhost:8080/api", {
method: 'POST',
body: formData,
})
.then((res) => {
console.log(res)
})
.then(() => {
console.log("Success")
})
.catch((error) => console.error(error))
}
Here is the code for the server
func api(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
fmt.Println("Connected -> api route")
fmt.Fprintf(w, "connected to api")
// ERROR HERE: no such file / failed to retrieve image
r.ParseMultipartForm(32 << 20)
file, _, err := r.FormFile("myImage")
if err != nil {
log.Print(err)
fmt.Println("failed to retrieve image")
w.WriteHeader(http.StatusBadRequest)
return
} else if err == nil {
fmt.Println("Success")
}
defer file.Close()
}
I have tried adding and removing the multipart/form-data headers, neither have worked.
I'm new to Go and still trying to figure things out, any help is appreciated!

Checking the code, this is a pretty standard upload file method, is your Go api working with other services?, I can not find anything wrong, so maybe is more about how the api is configured in general.
Other thing you can do is handling the error at
if err := r.ParseMultipartForm(32 << 20); err != nil {
fmt.Println(err)
}
maybe you can have a better idea about the error
Also make sure your file is really there before appending it
console.log(e.target.files)

Related

422 Unprocessable Entity error when uploading File using JavaScript Fetch API to FastAPI backend

The codes are as shown below.
Backend
api.py
#app.post("/caption")
async def caption(image: UploadFile = File(...)) -> str:
# produce the caption
caption = apiCaption(image)
# save the image and caption information
status = await apiSaveData(image, caption)
return caption if status else "Something went wrong"
Frontend
submit.js
export default function SubmitButton({ image }) {
const handleSubmission = async () => {
let formData = new FormData();
console.log(image);
formData.append("file", image);
await fetch("http://localhost:8000/caption", {
method: "POST",
body: formData,
})
.then(response => response.json())
.then(result => {
console.log("Caption:", result);
})
.catch(error => {
console.error("Error:", error);
});
};
return (
<div>
<button disabled={!image} onClick={handleSubmission}>
Submit
</button>
</div>
);
}
The server keeps showing:
Failed to load resource: the server responded with a status of 422 (Unprocessable Entity) error
I really don't know why and the error code is quite ambiguous so cannot get the point.
Make sure that on client side you use the same key (parameter's name) given on server side for UploadFile. In your case, that is image, as shown in this line of your code:
async def caption(image: UploadFile = File(...))
^^^^^
Hence, on client side, when appending the file to the FormData instance, you should use that key instead:
formData.append("image", image);
Please have a look at this answer for more details and examples. Also, for future reference, the 422 status code is not quite ambiguous, as you stated. The 422 response body will contain an error message about which field(s) is missing or doesn’t match the expected format, which will help you to resolve the issue.

Having trouble uploading files from Javascript and receiving it through Go

I set up a simple frontend service in JavaScript using Axios. This service takes a list of files and sends to my server code using a post request. My JavaScript looks like this
const testPost = async (files) => {
let formData = new FormData();
files.forEach((file) => {
formData.append("file", file);
});
const res = await axios({
method: "POST",
url: baseUrl,
data: formData,
headers: {
"Content-Type": "multipart/form-data",
},
});
return res;
};
And my Go code looks like this:
func (h *SendHandler) TestPost(w http.ResponseWriter, r *http.Request) {
//Allow CORS here By * or specific origin
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
formdata := r.MultipartForm
fmt.Println(formdata)
}
I think my problem lies in the body of my TestPost function in Go because I click send in my frontend code, I receive a response. In my Go function, when I print my formdata, it outputs <nil>. I want to be able to access each file in the list but I can't even access the formdata. I'm still new to both web dev and Go so there is definitely something I am misunderstanding here. Any pointers?
The documentation for MultipartForm says:
MultipartForm is the parsed multipart form, including file uploads. This field is only available after ParseMultipartForm is called.
Fix by calling ParseMultipartForm before using r.MultipartForm.
err := r.ParseMultipartForm(maxMemory)
if err != nil {
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
// r.MultipartForm is now set.
fmt.Println(r.MultipartForm) // does not print nil

Is it able to read javascript file object in phython?

There is a client sending a file object in JavaScript.
There is a server written in Python.
Please have a look following code of both client and server.
Client(JavaScript):
function sendFile(file) {
fetch('http://localhost:8088', {
method: 'POST',
body: JSON.stringify({
name: "file",
code: file
})
})
.then(res => {
// handle response
var reader = res.body.getReader();
reader.read()
.then(({done, value}) => {
// need to check done
let chunks = new Uint8Array(value.length);
chunks.set(value, 0);
let result = new TextDecoder("utf-8").decode(chunks);
console.log(result);
});
})
.catch(err => {
// handle error
console.log('fetch error:', err);
});
}
document.getElementById('sendBtn').addEventListener('change',
()=>{this.sendFile(document.getElementById('fileInput').files[0]);});
Server(Python):
#!/usr/bin/python
import BaseHTTPServer
import json
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.getheader('content-length'))
body = self.rfile.read(length)
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write("post response")
data = json.loads(body)
# print data['file'] just returns '{ }'
# I would like to save this file on sever side.
# Is it possible??
server = BaseHTTPServer.HTTPServer(("localhost", 8088), MyHandler)
server.serve_forever()
I would like to want to know if there is a way to read file object written in javascript on python world.
I had to send file content How can I serialize an input File object to JSON?
And it is able to read and save it using dcodestring
How to parse data-uri in python?
Thank you all.

Uploading Image to Cloudinary Express.js React Axios post request

I am trying to upload images to cloudinary using react front-end and express server.
The problem is i cant properly post request image to my express server.
This is how i prepare image to send it later:
var data = new FormData();
console.log(event.target.files[0]) // this prints FileObject succesfully
data.append('image', event.target.files[0]);
console.log(data) // this prints {} but i guess its natural since its FormData ??
this.imageToUpload = data;
This is how i post request:
axios.post('/api/courses/uploadImage',this.imageToUpload, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then( (response) => {
alert(JSON.stringify(response));
})
.catch(function (error) {
console.log(error);
});
Now in server side,req.body is empty.
router.post("/courses/uploadImage",(req,res,next)=>{
console.log(req.body) // empty
var image = req.body;
cloudinary.uploader.upload(image, function(error, result) { console.log(result) });
})
Also what should i really put to first parameter of(image in this case) uploader.upload ?
Not a direct answer but if you want Cloudinary also offers a way to directly upload images from your front-end so it saves you some work. You can read here further.
I've worked with their widget and it is very simple to integrate into almost any app.
You can do like this. I have successfully tried in my project.
function upload(){
var data = new FormData();
data.append('image', event.target.files[0]);
data.append('username', 'Saurabh'); //if you have other fields
axios.post('/api/courses/uploadImage', data,
headers: {
//your headers
})
.then( (response) => {
alert(JSON.stringify(response));
})
.catch(function (error) {
console.log(error);
});
}
In your express route you can simply get values like this
router.post('/api/courses/uploadImage', upload.single('image'), async(req,res, next) => {
const result = await cloudinary.v2.uploader.upload(req.file.path);
console.log(req.body.username); //Saurabh
//your logic
});
I solved my problem by directly uploading images to cloudinary from client with their html5 codepen example.

Node: Downloading a zip through Request, Zip being corrupted

I'm using the excellent Request library for downloading files in Node for a small command line tool I'm working on. Request works perfectly for pulling in a single file, no problems at all, but it's not working for ZIPs.
For example, I'm trying to download the Twitter Bootstrap archive, which is at the URL:
http://twitter.github.com/bootstrap/assets/bootstrap.zip
The relevant part of the code is:
var fileUrl = "http://twitter.github.com/bootstrap/assets/bootstrap.zip";
var output = "bootstrap.zip";
request(fileUrl, function(err, resp, body) {
if(err) throw err;
fs.writeFile(output, body, function(err) {
console.log("file written!");
}
}
I've tried setting the encoding to "binary" too but no luck. The actual zip is ~74KB, but when downloaded through the above code it's ~134KB and on double clicking in Finder to extract it, I get the error:
Unable to extract "bootstrap" into "nodetest" (Error 21 - Is a directory)
I get the feeling this is an encoding issue but not sure where to go from here.
Yes, the problem is with encoding. When you wait for the whole transfer to finish body is coerced to a string by default. You can tell request to give you a Buffer instead by setting the encoding option to null:
var fileUrl = "http://twitter.github.com/bootstrap/assets/bootstrap.zip";
var output = "bootstrap.zip";
request({url: fileUrl, encoding: null}, function(err, resp, body) {
if(err) throw err;
fs.writeFile(output, body, function(err) {
console.log("file written!");
});
});
Another more elegant solution is to use pipe() to point the response to a file writable stream:
request('http://twitter.github.com/bootstrap/assets/bootstrap.zip')
.pipe(fs.createWriteStream('bootstrap.zip'))
.on('close', function () {
console.log('File written!');
});
A one liner always wins :)
pipe() returns the destination stream (the WriteStream in this case), so you can listen to its close event to get notified when the file was written.
I was searching about a function which request a zip and extract it without create any file inside my server, here is my TypeScript function, it use JSZIP module and Request:
let bufs : any = [];
let buf : Uint8Array;
request
.get(url)
.on('end', () => {
buf = Buffer.concat(bufs);
JSZip.loadAsync(buf).then((zip) => {
// zip.files contains a list of file
// chheck JSZip documentation
// Example of getting a text file : zip.file("bla.txt").async("text").then....
}).catch((error) => {
console.log(error);
});
})
.on('error', (error) => {
console.log(error);
})
.on('data', (d) => {
bufs.push(d);
})

Categories

Resources