FormData upload on Expo - spring-boot

Using expo, whenever I run a post request with a FormData object with an appended JSON and a image file, I get
"error": "Unsupported Media Type",
"message": "Content type 'application/octet-stream' not supported",
"path": "/visitas/",
"status": 415,
[…]
as a response from the backend (which runs Spring Boot), but whenever I replicate the request into a HTTP Client (Insomnia on this case) the request follow as it should, and I can retrieve and see the image back as I should.
Code
Visitas.js
[…]
async function startVisita(checkin) {
// Checkin contains file uri and some other things
try {
const location = await getLocation();
const formData = new FormData();
formData.append('object',
JSON.stringify({
longitude: location.coords.longitude,
latitude: location.coords.latitude,
checkin: new Date(),
loja: {id: loja.id},
})
);
// object gets filled accondingly
formData.append('imagecheckin', {
uri: checkin.uri,
name: 'imagem.jpg', // I know the image is .jpg
type: 'image/jpg',
});
// imagecheckin is a object inside formData (not a readStream as it normally would)
console.log(formData);
try {
const response = await fetch(`${Endpoint.baseAddr}${Endpoint.visitas}`, {
body: formData,
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': 'Bearer ' + await AsyncStorage.getItem('jwt'),
},
})
.then(res => res.json());
console.log(response);
} catch (err) {
console.error('Erro ao postar a visita! Erro causado:', err);
console.log(err.res, err.response);
}
} catch (err) {
console.error('Erro ao criar a visita! Erro causado:');
console.error(err);
}
}
[…]
ControllerImagens.java
[…]
#PostMapping
public ResponseEntity<T> adicionarCheckin(
#RequestPart(name = "imagecheckin", required = true) MultipartFile file,
#RequestPart(name = "object", required = true) T objeto,
#RequestHeader("authorization") String token) {
// Calls constructors, validators and stuff
[…]
And the formdata I get from the log is
FormData {
"_parts": Array [
Array [
"object",
"{\"longitude\":-40.3097038,\"latitude\":-20.3758293,\"checkin\":\"2020-04-29T18:06:22.994Z\",\"loja\":{\"id\":1}}",
],
Array [
"imagecheckin",
Object {
"name": "imagem.jpg",
"type": "image/jpg",
"uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252Fproatend-f576a9db-3f86-4238-8677-3ebbd056f4ea/Camera/1f2192a7-fe81-40d1-8efd-9ff6a98a32a3.jpg",
},
],
],
}

Related

Unable to upload pdf file in POST request using Cypress 6.4.0 & TypeScript

I am writing API tests using Cypress 6.4.0 & TypeScript where I need to upload a pdf file in the request body.
My code for the request is:
My code for the request body is:
public async createAssetDocTest() {
let url = sharedData.createAsset_url + sharedData.assetA;
let response = await fetch(url
,
{
method: 'POST',
body: await requestbody.createAssetDocBody(),
headers: {
Authorization: sharedData.bearer + " " + adminTokenValue,
Accept: sharedData.accept,
'Content-type': sharedData.docReqContent,
},
}
);
expect(response.status).to.equal(200);
public async createAssetDocBody(): Promise<any> {
const file = sharedData.doc;
cy.fixture(file).then((pdfDoc) => {
Cypress.Blob.binaryStringToBlob(
pdfDoc,
sharedData.contentTypeValue
).then(async (blob: string | Blob) => {
const formData = new FormData();
formData.set(sharedData.document, blob, file);
const body = {
formdata: {
document: {
value: pdfDoc,
options: {
filename: sharedData.document,
contentType: null,
},
},
},
};
return body;
});
});
}
However, the file does not upload the file & the request fails with error 400. Is there a better way to upload files in the body of the POST request?
enter image description here
Resolved this issue!
The main issue was that my Cypress version was too old. Upgraded to 9.7.0
Then added the following code:
public async createAssetDoc(): Promise<any> {
cy.fixture("pic location", "binary")
.then((file) => Cypress.Blob.binaryStringToBlob(file))
.then((blob) => {
var formdata = new FormData();
formdata.append("document", blob, "pic location");
const url = "your url";
cy.request({
url,
method: "POST",
body: formdata,
headers: {
Authorization:
"bearer" + " " + token,
Accept: "application/json",
"Content-Type": "multipart/form-data",
},
}).then((response) => {
expect(response.status).to.equal(201);
expect(response.statusText).to.equal(
sharedData.fileUploadStatusText
);
const finalResponse = String.fromCharCode.apply(
null,
new Uint8Array(response.body)
);
return finalResponse;
});
});
}

Posting image from expo and axios to spring boot server returns error

I wanna send an axios request with photo data to my Spring Boot server but it does not work.
Here is the code:
const updateUserProfile = dispatch => async ({categories, phoneNumber, photo}) => {
try {
const id = await SecureStore.getItemAsync('user_id');
const formData = new FormData()
formData.append("file", {
uri: photo,
name: `${id}_photo`,
type: 'image/png'
})
await request.post(
`/photos/${id}`,
formData,
{
headers: {
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`
},
},
)
dispatch({type: 'update_user_profile', payload: response.data})
} catch (e) {
dispatch({type: 'add_error', payload: 'UPDATE_USER_PROFILE_ERROR'})
}
}
The file URI looks like that and I think its correct:
file:///data/user/0/[...]/ImagePicker/e9255306-dca9-486e-a9
05-e4e1c619b766.jpg
And here is the Spring Boot Controller
#PostMapping("/{userId}")
public void saveObject(#RequestParam(value = "file") MultipartFile file, #PathVariable Long userId) {
photoService.uploadFile(file, userId);
}
Spring Boot works great when I send request with photo from postman but when I want to send the request from updateUserProfile method above, I receive this error:
Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]
Okay, finally after many hours I fixed the problem. This github issue helped me a lot https://github.com/axios/axios/issues/4412
So I installed form-data package
npm i form-data
and in the updateUserProfile method added this line just before appending data to formData
FormData.prototype[Symbol.toStringTag] = 'FormData';
so the full method looks like that now:
const updateUserProfile = dispatch => async ({categories, phoneNumber, photo}) => {
try {
const id = await SecureStore.getItemAsync('user_id');
const extenstion = photo.substring(photo.lastIndexOf('.') + 1)
const fileName = photo.replace(/^.*[\\\/]/, '')
const formData = new FormData()
FormData.prototype[Symbol.toStringTag] = 'FormData';
formData.append("file", {
uri: photo,
name: fileName,
type: `image/${extenstion}`
})
await request.post(
`/photos/${id}`,
formData,
{
headers: {
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`
},
},
)
dispatch({type: 'update_user_profile', payload: response.data})
} catch (e) {
dispatch({type: 'add_error', payload: 'UPDATE_USER_PROFILE_ERROR'})
}
}

DynamoDB update data works but return Internal Server Error

I am using API server with AWS Lambda and DynamoDB
I've created an API for Update data.
export const updateD = async(event, context, callback)=>{
const {email, uid} = JSON.parse(event.body);
let unique = await getUnique();
const updateParams = {
TableName: "MY_TABLE",
Key: {
email: email,
uid: uid
},
UpdateExpression: "set code = :code, expiredAt = :now", //expiredAt is TTL
ExpressionAttributeValues: {
":isVerified": unique,
":now": moment().add(10, "minutes").unix()
},
ReturnValues: "ALL_NEW"
}
DYNAMO_DB.update(updateParams, (err, data) => {
if(err) {
const r = {
statusCode: 500,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify(err)
}
callback(null, r);
}
const r = {
statusCode: 200,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({msg: "success"})
}
callback(null, r);
});
}
When I called this API, the data is updated successfully by it, but I can receive only
{
"message": "Internal server error"
}
What I missed in my code??
Your handler is defined as an async function due to which lambda is expected to return a response.
However the function body follows non-async pattern passing the response to the callback instead of returning it.
If you want to use async/await you should update your function by using the promisified version of update operation instead of callback, it may like look like as follows:
export const updateD = async (event) => {
const {email, uid} = JSON.parse(event.body);
let unique = await getUnique();
const updateParams = {
TableName: "MY_TABLE",
Key: {
email: email,
uid: uid
},
UpdateExpression: "set code = :code, expiredAt = :now", //expiredAt is TTL
ExpressionAttributeValues: {
":isVerified": unique,
":now": moment().add(10, "minutes").unix()
},
ReturnValues: "ALL_NEW"
};
try {
const data = await DYNAMO_DB.updateItem(updateParams).promise();
return {
statusCode: 200,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({msg: "success"})
}
} catch (err) {
return {
statusCode: 500,
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify(err)
}
}
};

Error during upload image to imgur - inavlid URL

i have some troubles with imgur api. I converted image to base64 code and tried upload it to imgur api. Unfortuatelly I'm receiving an error:
"error": "Invalid URL (data:image/png;base64,iVBORw0KGgoAA..."
Here's my function:
uploadImageToImgur: function (file) {
const url = 'https://api.imgur.com/3/image',
reader = new FileReader();
reader.onloadend = async function () {
let { result } = reader;
try {
const request = await fetch(url, {
method: 'POST',
headers: {
"Authorization": 'my client key',
},
body: result
});
const response = await request.json();
console.log(response);
} catch (e) {
throw new Error(e);
}
}
if (file) {
reader.readAsDataURL(file);
}
}
You need to cut this part out.
You are missing some parameters. Also, make sure your headers have the Client-ID key.
const request = await fetch(url, {
method: 'POST',
headers: {
"Authorization": 'Client-ID {yourKey}',
},
form: {
"image": result,
"type": "base64"
}
});

BadArgument and JSON parsing error when making an API call

Inside my component, I'm trying to make an api call using fetch.
The API takes in an image .jpg file path as such - file:///var/mobile/Containers/Data/Application/1E1E919E-6C21-4CC7-B9C2-5B4B3BC84B0F/Library/Caches/ExponentExperienceData/%2540chuks93%252Fihu-main/Camera/F3B8EBCC-BB09-4603-AF7E-FD3CA792C237.jpg and it should return a JSON object.
Here's my fetch call below:
export default {
processImage: (image) => {
// Replace the subscriptionKey string value with your valid subscription key.
var subscriptionKey = "*******************";
var uriBase = "https://westus.api.cognitive.microsoft.com/face/v1.0/detect?returnFaceId=true&returnFaceLandmarks=false&returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,occlusion,accessories,blur,exposure,noise";
// Display the image.
var sourceImageUrl = image;
console.log(typeof sourceImageUrl)
console.log("here", sourceImageUrl);
// Perform the REST API call.
return fetch(uriBase, {
method: 'POST',
headers: {
"Content-type": "application/json",
"Ocp-Apim-Subscription-Key": subscriptionKey
},
body: JSON.stringify(sourceImageUrl),
})
.then((data) => data.json())
.then(function (data){
console.log("hello", data);
})
.catch(function (error) {
console.log(error);
});
}
}
When I run the above code this is the error it returns:
Object {
"error": Object {
"code": "BadArgument",
"message": "JSON parsing error.",
}
Any thoughts on this?
Change your
body: JSON.stringify(sourceImageUrl),
to
body: JSON.stringify({url: sourceImageUrl}),
to make the body of the post a proper json object.

Resources