I am trying to figure this out with axios. I have made the direct api call with superagent and now want to know how to use with axios as the rest of my project is with axios. I know there is cloudinary-react, but this is the way I prefer to do it.
Here is what I have so far.
import React, { Component } from 'react';
import Dropzone from 'react-dropzone';
import sha1 from 'sha1';
import superagent from 'superagent';
import axios from 'axios';
class Images extends Component {
uploadFile(files) {
console.log('uploadFile: ');
const image = files[0];
const cloudName = 'tbaustin';
const url = `https://api.cloudinary.com/v1_1/${cloudName}/image/upload`;
const timestamp = Date.now()/1000;
const uploadPreset = 'cnh7rzwp';
const paramsStr = `timestamp=${timestamp}&upload_preset=${uploadPreset}secret`;
const signature = sha1(paramsStr);
const params = {
'api_key': 'api_key',
'timestamp': timestamp,
'upload_preset': uploadPreset,
'signature': signature
}
let uploadRequest = superagent.post(url)
uploadRequest.attach('file', image);
Object.keys(params).forEach((key) => {
uploadRequest.field(key, params[key]);
});
uploadRequest.end((err, res) => {
if(err) {
alert(err);
return
}
console.log('UPLOAD COMLETE: '+JSON.stringify(res.body));
});
//AXIOS CONTENT HERE
// let request = axios.post(url, {file: image});
// request.then((response) => {
// Object.keys(params).forEach((key) => {
// uploadRequest.field(key, params[key]);
// });
// console.log('UPLOAD COMPLETE: '+JSON.stringify(response.body));
// }).catch((err) => { alert(err); });
}
render() {
return (
<div>
<Dropzone onDrop={this.uploadFile.bind(this)}/>
</div>
)
}
}
export default Images;
This worked for me.
let formData = new FormData();
formData.append("api_key",'');
formData.append("file", image);
formData.append("public_id", "sample_image");
formData.append("timestamp", timeStamp);
formData.append("upload_preset", uploadPreset);
axios
.post(url, formData)
.then((result) => {
console.log(result);
})
.catch((err) => {
console.log(err);
})
This is a part of my project when I tried to upload an avatar. I have set my upload preset to unsigned on cloudinary.
const uploadPhotoHandler = async (e) => {
const file = e.target.files[0];
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", "pa*****");
try {
setPictureProfile("./assets/img/giphy.gif");
const res = await axios.post("https://api.cloudinary.com/v1_1/${cloud_name}/upload", formData);
console.log(res.data.url);
setPictureProfile(res.data.url);
} catch (error) {}
};
Related
I'm not sure if this is even possible, but here's what I'm trying to do:
Let the user enter some text
Generate a PNG from that text
Upload it to Pinata, which requires it to be in ReadStream format
Do all of this on the front-end
I've managed to accomplish (1) and (2) using html2canvas.
The tricky part is (3). The reason it has to be in ReadStream format is because that's the format Pinata's SDK wants:
const fs = require('fs');
const readableStreamForFile = fs.createReadStream('./yourfile.png');
const options = {
pinataMetadata: {
name: MyCustomName,
keyvalues: {
customKey: 'customValue',
customKey2: 'customValue2'
}
},
pinataOptions: {
cidVersion: 0
}
};
pinata.pinFileToIPFS(readableStreamForFile, options).then((result) => {
//handle results here
console.log(result);
}).catch((err) => {
//handle error here
console.log(err);
});
I realize that this would be no problem to do on the backend with node, but I'd like to do it on the front-end. Is that at all possible? Or am I crazy?
I'm specifically using Vue if that matters.
For anyone interested the solution ended up being using fetch+blob:
const generateImg = async () => {
const canvas = await html2canvas(document.getElementById('hello'));
const img = canvas.toDataURL('image/png');
const res = await fetch(img);
return res.blob();
};
This blob can then be passed into a more manual version of their SDK:
const uploadImg = (blob: Blob) => {
const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`;
const data = new FormData();
data.append('file', blob);
const metadata = JSON.stringify({
name: 'testname',
});
data.append('pinataMetadata', metadata);
const pinataOptions = JSON.stringify({
cidVersion: 0,
});
data.append('pinataOptions', pinataOptions);
return axios
.post(url, data, {
maxBodyLength: 'Infinity' as any, // this is needed to prevent axios from erroring out with large files
headers: {
// #ts-ignore
'Content-Type': `multipart/form-data; boundary=${data._boundary}`,
pinata_api_key: apiKey,
pinata_secret_api_key: apiSecret,
},
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
};
I have recently completed a node js course and wanted to work on projects to improve my skills. I started a dev.io challenge, an image uploader using react and express and I am trying to implement drag and drop but I get the error POST http://localhost:3000/upload 404 (Not Found) when trying to upload the file to the public/uploads folder. Here is my code.
Dropzone.js
import image from './images/image.svg';
import React, { useState } from 'react';
import axios from 'axios';
const Dropzone = () => {
const [file, setFile] = useState('');
const [uploadedFile, setUploadedFile] = useState({});
const dropHandler = async (ev) => {
// Prevent default behavior (Prevent file from being opened)
ev.preventDefault();
if (ev.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
for (let i = 0; i < ev.dataTransfer.items.length; i++) {
// If dropped items aren't files, reject them
if (ev.dataTransfer.items[i].kind === 'file') {
let fileSync = ev.dataTransfer.items[i].getAsFile();
setFile(ev.dataTransfer.files[i]);
}
}
}
const formData = new FormData();
formData.append('file', file);
try {
const res = await axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
const { fileName, filePath } = res.data;
setUploadedFile({ fileName, filePath });
} catch (err) {
if (err.response.status === 500) {
console.log('There was a problem with the server');
} else {
console.log(err.response.data.msg);
}
}
};
const dragOverHandler = (e) => {
// Prevent default behavior (Prevent file from being opened)
e.preventDefault();
};
return (
// Drag and drop zone
<div
className="image-upload-area"
onDrop={dropHandler}
onDragOver={dragOverHandler}
>
<img className="upload-icon" src={image} />
<p className="upload-info">Drag & Drop your image here</p>
</div>
);
};
export default Dropzone;
server.js
const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();
app.use(fileUpload());
// Upload Endpoint
app.post('/upload', (req, res) => {
if (req.files === null) {
return res.status(400).json({ msg: 'No file uploaded' });
}
const file = req.files.file;
file.mv(`${__dirname}/client/public/uploads/${file.name}`, (err) => {
if (err) {
console.error(err);
return res.status(500).send(err);
}
res.json({ fileName: file.name, filePath: `/uploads/${file.name}` });
});
});
app.listen(5000, () => console.log('Server Started...'));
I am working on an app and I am using expo, I want to make sure each user can upload an image to firebase, and later publish this image on the profile page.
Using expo this is how I upload images:
const pickImage = async () => {
let pickerResult = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(pickerResult);
handleImagePicked(pickerResult);
};
the result in the console is:
Object {
"cancelled": false,
"height": 312,
"type": "image",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fallergyn-app-77bfd368-65fd-43f9-8c34-9c35cef42c25/ImagePicker/daaa229c-c352-4994-ae18-ca2dbb3534ce.jpg",
"width": 416,
}
and this is how I upload to the firebase:
const handleImagePicked = async (pickerResult) => {
try {
if (!pickerResult.cancelled) {
setImage(pickerResult.uri);
await uploadImageAsync(pickerResult.uri);
console.log("done");
}
} catch (e) {
console.log(e);
alert("Upload failed, sorry :(");
} finally {
}
};
async function uploadImageAsync(uri) {
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", uri, true);
xhr.send(null);
});
const ref = firebase
.storage()
.ref()
.child("images" + Math.random());
const snapshot = await ref.put(blob);
// We're done with the blob, close and release it
blob.close();
return await snapshot.ref.getDownloadURL();
}
this code works it saves the path of the image this: "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fallergyn-app-77bfd368-65fd-43f9-8c34-9c35cef42c25/ImagePicker/daaa229c-c352-4994-ae18-ca2dbb3534ce.jpg" in the firebase under user collection using the uid of the user.
I am not sure if this is good, because I want to make sure the image itself is uploaded to firebase, I saw some threads in StackOverflow regarding this issue either too old or no answers, so I am hoping to get some sort of solution to what I need to do.
if I use
const ref = firebase
.storage()
.ref()
.child("images" + Math.random());
.putFile(uri);
this tells me that putFile is not a function. the same with put(uri)
Try this one. This function returns the path of the saved image from firebase which you will store in the user's document instead.
const handleImagePicked = async (pickerResult) => {
if (!pickerResult.cancelled) {
setImage(pickerResult.uri);
const result = await uploadImageAsync(pickerResult.uri);
if(result) {
console.log('success');
//save the result path to firestore user document
return;
}
alert("Upload failed, sorry :(");
}
};
export const uploadImageAsync = async (uri: string) => {
let filename = uri;
if (Platform.OS === 'ios') {
filename = uri.replace('file:', '');
}
const ext = filename.split('.').pop();
const path = `images/${id}.${ext}`;
const ref = firebase.storage().ref(path);
try {
const response = await fetch(filename);
const blob = await response.blob();
await ref.put(blob);
return path;
} catch {
return null;
}
};
This worked for me , using rn-fetch-blob
import launchImageLibrary from 'react-native-image-picker';
import RNFetchBlob from 'rn-fetch-blob';
import storage from '#react-native-firebase/storage';
const pickImage = () => {
let options = {
mediaType: 'photo',
quality: 0.5,
};
launchImageLibrary(options, (response) => {
console.log('Response = ', response);
uploadImagePicked(response);
});
};
const uploadImagePicked = (response) => {
if (response.fileName) {
const fileName = response.fileName;
var storageRef = storage().ref(`receiptImages/${fileName}`);
RNFetchBlob.fs.readFile(response.uri , 'base64')
.then(data => {
storageRef.putString(data, 'base64', {contentType:"image/jpg"})
.on(
storage.TaskEvent.STATE_CHANGED,
snapshot => {
console.log("snapshot: " + snapshot.state);
console.log("progress: " + (snapshot.bytesTransferred / snapshot.totalBytes) * 100);
if (snapshot.state === storage.TaskState.SUCCESS) {
console.log("Success");
}
},
error => {
console.log("image upload error: " + error.toString());
},
() => {
storageRef.getDownloadURL()
.then((downloadUrl) => {
console.log("File available at: " + downloadUrl);
})
})
})
.catch(error => {
console.log(error);
})
}
else {
console.log("Skipping image upload");
}
}
I tried to rewrite this Submit function to use react query useMutation but i get errors.Does somebody know how to change this to be writen with useMutation.I thank you very much for every hint and every answer to this question.
async function handleSubmit(e) {
e.preventDefault();
try {
if (file) {
// if file is set send it to cloudinary api
const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
loading(true);
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", UPLOAD_PRESET);
const res = await fetch(url, {
method: "POST",
body: formData,
});
// get data and pull out 1000w image url
const data = await res.json();
const fileUrl = await data.eager[0].secure_url;
console.log(fileUrl);
setError("");
if (album.trim() !== "" && color.trim() !== "" && fileUrl) {
// Craeting Date form
const albumData = new FormData();
albumData.append("name", album);
albumData.append("bckImgUrl", fileUrl);
albumData.append("color", color);
// change albumData to json
const object = {};
albumData.forEach((value, key) => (object[key] = value));
// sending data to /api/v1/albums
const res = await fetch(`${SERVER_API}/api/v1/albums`, {
method: "POST",
body: JSON.stringify(object),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
const message = `An error has occured: ${res.status}`;
setError(message);
}
const data = await res.json();
const id = await data.data._id;
loading(false);
history.push(`/albums/${id}`);
} else {
setError("Please enter all the field values.");
}
} else {
setError("Please select a file to add.");
}
} catch (error) {
error.response && setError(error.response.data);
}
}
Something like that. As simple as possible
Codesandbox link for demo
import { Fragment, useState } from "react";
import axios from "axios";
import { useMutation } from "react-query";
const senRequest = async () => {
return await axios.get("https://jsonplaceholder.typicode.com/posts");
};
export default function App() {
const [val, setVal] = useState("");
const [result, setResult] = useState([]);
const { mutate } = useMutation(senRequest); // if you need to send data configure it from here
const handleSubmit = (e) => {
e.preventDefault();
mutate(senRequest, { // And send it in here.
onSuccess: ({ data }) => {
setResult(data.slice(0, 5));
}
});
};
return (
<div className="App">
<form onSubmit={handleSubmit}>
<input value={val} onChange={(e) => setVal(e.target.value)} />
<button type="submit">Submit</button>
</form>
{result.map((el) => (
<Fragment key={el.id}>
<div
style={{
width: "100%",
borderBottom: "1px solid gray"
}}
>
<span>{el.title}</span>
<span>{el.body}</span>
</div>
</Fragment>
))}
</div>
);
}
little refactor suggestion :)
import React from "react";
import { useHistory } from "react-router-dom";
import { UPLOAD_PRESET, CLOUD_NAME, SERVER_API } from "../../config";
// to don't redefine this function on each rerender they can be defined out of component
const uploadImage = async file => {
const url = `https://api.cloudinary.com/v1_1/${CLOUD_NAME}/upload`;
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", UPLOAD_PRESET);
const res = await fetch(url, {
method: "POST",
body: formData,
});
if (!res.ok) {
throw new Error(`Can't upload image. ${res.status}`)
}
const data = await res.json();
return await data.eager[0].secure_url;
}
const createAlbum = async data => {
const res = await fetch(`${SERVER_API}/api/v1/albums`, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
throw new Error(`An error has occurred: ${res.status}`)
}
const json = await res.json();
return json.data._id;
}
const Form = ({ file, loading: setLoading, setError, album, color, children }) => {
let history = useHistory();
const clearError = () => setError("")
const handleSubmit = async e => {
e.preventDefault();
clearError();
try {
if (!file) {
throw new Error("Please select a file to add.");
}
if (!album.trim() || !color.trim()){
throw new Error("Please enter all the field values.");
}
setLoading(true);
const fileUrl = await uploadImage(file);
const data = {
"name": album,
"bckImgUrl": fileUrl,
"color": color
};
const albumId = await createAlbum(data);
history.push(`/albums/${albumId}`);
} catch (error) {
setError(error.message);
} finally {
setLoading(false)
}
}
return <form onSubmit={handleSubmit}>{children}</form>
}
export default Form
I am sending a file to an api endpoint via react webapp and for now as a mock up have been using file upload. I have since added camera capabilities as I plan for users to be able to take a picture and upload that picture. I'm using the react-html5-camera-photo which captures a datauri element. How do I convert this to a file to upload to the endpoint? Or am I approaching this incorrectly?
File Upload:
handleUploadImage=()=> {
console.log(this.state.selectedFile)
const data = new FormData();
data.append('file', this.state.selectedFile);
data.append('filename', this.state.selectedFile.name);
fetch('http://localhost:5000/upload', {
method: 'POST',
body: data,
})
.then((response) => {
response.json()
.then((response) => {
//this.setState({ imageURL: `http://localhost:5000/${body.file}` });
console.log(response.text)
this.setState({ text: response.text})
this.getPlate()
})
});
}
Camera Code:
startCamera = () => {
console.log('starting camera')
if(!this.state.cameraLoad) {
this.setState({ cameraLoad: true, camIconData: collapse}) ;
} else {
this.setState({ cameraLoad: false, camIconData: expand}) ;
}
}
onTakePhoto = (dataUri) => {
// Do stuff with the dataUri photo...
console.log('photo taken');
this.setState({ camColor: 'green', dataUri : dataUri })
}
// will upload photo after user confirms to upload
uploadPhoto = e => {
console.log('uploading photo')
console.log(this.state.dataUri)
this.setState({ camColor: 'green', dataUri: null, cameraLoad: false });
};
The dataUri element looks something like:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAAAALQCAYAAADPfd1WAAAgAElEQVR4XlS9h5Nk63HdmeVdV5vpmXnzDAEQBAiKwlJmIzZiQ/u/72qDWongkpREQFjRgHh2/LQp7zd+52TeavSLfjPTXXXr3s/kl3n
Here is the complete example. Please write a CameraComponent as below where you will find submitPhoto() function and this function is responsible for uploading image to the api.
import React, {useState} from 'react';
import Camera from 'react-html5-camera-photo';
import 'react-html5-camera-photo/build/css/index.css';
import ImagePreview from "./ImagePreview";
import axios from 'axios';
function CameraComponent(props) {
const [dataUri, setDataUri] = useState('');
const isFullscreen = false;
const cameraRef = React.useRef();
function handleTakePhoto(dataUri) {
console.log('takePhoto');
}
function handleTakePhotoAnimationDone(dataUri) {
console.log(dataUri, 'takePhoto');
setDataUri(dataUri);
}
function handleCameraError(error) {
console.log('handleCameraError', error);
}
function handleCameraStart(stream) {
console.log('handleCameraStart');
}
function handleCameraStop() {
console.log('handleCameraStop');
}
function submitPhoto() {
const url = "http://localhost:3000/api/img";
const request = axios.post(url, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
img: dataUri
})
}).catch(error => {
console.warn(error);
});
}
return (
<div>
<button onClick={submitPhoto}>Upload</button>
{(dataUri)
? <ImagePreview dataUri={dataUri}
isFullscreen={isFullscreen}
/> :
<Camera ref={cameraRef}
onTakePhoto={(dataUri) => {
handleTakePhoto(dataUri);
}}
onTakePhotoAnimationDone={(dataUri) => {
handleTakePhotoAnimationDone(dataUri);
}}
onCameraError={(error) => {
handleCameraError(error);
}}
onCameraStart={(stream) => {
handleCameraStart(stream);
}}
onCameraStop={() => {
handleCameraStop();
}}
/>
}
</div>
);
}
export default CameraComponent;
Here is the another component ImagePreview which will preview the image
import React from 'react';
import PropTypes from 'prop-types';
import './styles/imagePreview.css';
export const ImagePreview = ({ dataUri, isFullscreen }) => {
let classNameFullscreen = isFullscreen ? 'demo-image-preview-fullscreen' : '';
return (
<div className={'demo-image-preview ' + classNameFullscreen}>
<img src={dataUri} />
</div>
);
};
ImagePreview.propTypes = {
dataUri: PropTypes.string,
isFullscreen: PropTypes.bool
};
export default ImagePreview;
use this :
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
var convertedFile = dataURLtoFile(dataUri, `${Math.random(10)}.jpg`);