Axios send strange array to React - reactjs

I geting the data back from my API in React from a post request and I get just the first object of the entire Array.prototype
My API for the upload:
router.post("/uploads", upload.any(), async (req, res) => {
try {
if (!req.files) {
res.send({
status: false,
message: "No file uploaded",
});
} else {
let data = req.files;
res.send({
status: true,
message: "Files are uploaded",
data: data,
});
}
} catch (error) {
res.status(500).send(err);
}
});
POSTMAN gives me back:
{
"status": true,
"message": "Files are uploaded",
"data": [
{
"fieldname": "uploads\n",
"originalname": "46335256.jpg",
"encoding": "7bit",
"mimetype": "image/jpeg",
"destination": "client/uploads/",
"filename": "46335256-2020-08-04.jpg",
"path": "client/uploads/46335256-2020-08-04.jpg",
"size": 19379
},
{
"fieldname": "uploads\n",
"originalname": "120360358.jpg",
"encoding": "7bit",
"mimetype": "image/jpeg",
"destination": "client/uploads/",
"filename": "120360358-2020-08-04.jpg",
"path": "client/uploads/120360358-2020-08-04.jpg",
"size": 78075
}
]
}
perfect!
this is my function in React to upload
const uploadFiles = () => {
uploadModalRef.current.style.display = "block"
uploadRef.current.innerHTML = "File(s) Uploading..."
for (let i = 0; i < validFiles.length; i++) {
const formData = new FormData()
formData.append("images", validFiles[i])
axios
.post("http://localhost:5000/api/db/uploads", formData, {
onUploadProgress: progressEvent => {
const uploadPercentage = Math.floor(
(progressEvent.loaded / progressEvent.total) * 100
)
...// code for graphic upload
},
})
.then(resp => {
console.log(resp.data.data)
resp.data.data.map(item => {
console.log(item)
})
})
.catch(() => {
... // code
}
}
and with this I get (from the console):
[{…}]
0:
destination: "client/uploads/"
encoding: "7bit"
fieldname: "images"
filename: "46335256-2020-08-04.jpg"
mimetype: "image/jpeg"
originalname: "46335256.jpg"
path: "client/uploads/46335256-2020-08-04.jpg"
size: 19379
__proto__: Object
length: 1
__proto__: Array(0)
is an array(if I map it works) but with just the first object.
How is it possible ??
I tried even with async/await but nothing changes
Where I'm mistaking?
Thanks!

Related

Push an object to an array in api in react onSubmit

I have an api with the following schema.
[
{
"id":1,
"question": {
"description" : "",
"user": "",
},
"answers:[
{
"detailedAnswer" : "",
"user" : "",
},
{
"detailedAnswer" : "",
"user" : "",
}
]
},
{
"id":2,
"question": {
"description" : "",
"user": "",
},
"answers:[
{
"detailedAnswer" : "",
"user" : "",
}
]
}
]
So In my react app I need to add new object (given below) to the answers array of that particular id everytime I click submit button.
{
"detailedAnswer" : "",
"user" : "",
},
So my question is how can I push new object to the answers array ?
So, I tried Post method it shows "Bad request 400 error" and when I use "PUT" method, the object instead of appending item to the array replaces the exisitng object.
const postAnswer = async (e) => {
e.preventDefault();
const addAnswer = {
detailedanswer: answer,
user: user,
};
await fetch(`${API}/home/${id}`, {
method: "POST",
body: JSON.stringify(addAnswer),
headers: {
"Content-Type": "application/json",
},
})
.then((response) => {
response.json()
console.log(response)
})
.then((data) => {
console.log(data)
})
.then(() => alert("Answer added successfully"))
.then(() => navigate(`/home/${id}`))
.catch((err) => console.log(err.message))
}
This is the error I got
POST https://635b6c48aa7c3f113dbc75cb.mockapi.io/home/5 400 ( Bad Request )
Response {type: 'cors', url: 'https://635b6c48aa7c3f113dbc75cb.mockapi.io/home/5', redirected: false, status: 400, ok: false, …}
There is no error in the URL mentioned still I am getting bad request error.

React + fetch: adding extra characters and backslashes to my url

I have this code in React 17
useEffect(() => {
getLocalJson('../json/login/login.json', props.headers)
.then(resp => {
setFields(resp);
});
}, [props.headers]);
And the getLocalJson method is in a different file:
export const getLocalJson = async (url, headers) => {
console.log(url)
const resp = await fetch(url, {'headers': headers});
const json = await resp.json();
return json;
}
However the call to load the local JSON file from the public folder is:
Request URL: http://localhost:3000/json/login/%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5C%5Cdx%5Cjson%5Clogin%5Clogin.json
Ths is the JSON
[
{
"order": 0,
"systemName": "title",
"friendlyName": "Login",
"dataType": {
"type": "TITLE"
}
},
{
"order": 1,
"required": true,
"systemName": "username",
"friendlyName": "Username",
"errorMsg": "Invalid username",
"dataType": {
"type": "TEXT"
}
},
{
"order": 2,
"required": true,
"systemName": "password",
"friendlyName": "Password",
"errorMsg": "Invalid password",
"dataType": {
"type": "PASSWORD"
}
},
{
"order": 3,
"systemName": "title",
"friendlyName": "Login",
"dataType": {
"type": "BUTTON",
"submit": true
}
}
]
And it makes the call over and over and over
This exact code works on my ubuntu dev box, but is failing as abovw on my windows box
I think there is some issue with the way you are passing down the headers, look into the documentation to have a better idea.
Put your function in the body of your component where you're using useEffect and wrap it with useCallback like this:
const getLocalJson = useCallback( async (url, headers) => {
console.log(url)
const resp = await fetch(url, {'headers': headers});
const json = await resp.json();
return json;
},[])

How to get a record from an array result of API in React Native with condition?

This is the result JSON file from API:
{
"data": [
{
"recordid": "8888abc",
"accountno": "00-00-00000-00007-00",
"tag": "govid",
"filename": "gov_id.png",
"path": "C:\\MOBILEAPP\\governmentid/gov_id.png",
"ext": ".png",
"posted_dt": "12/11/2019 10:38:20 AM"
},
{
"recordid": "8888abc",
"accountno": "00-00-00000-00007-00",
"tag": "compid",
"filename": "compid.jpg",
"path": "C:\\MOBILEAPP\\compid/cid.jpg",",
"ext": ".jpg",
"posted_dt": "12/11/2019 10:38:20 AM"
}
],
"error_message": "Successfully retrieved.",
"is_success": true,
"requested_on": "12/18/2019 2:14:27 PM"
}
I need to get the path where tag = 'govid' to be puth in a variable because it is used in the header of another API fetching.
async getProfilePhotoPath(token) {
//membid is recordid
let membid = await AsyncStorage.getItem(MEMBER_ID);
let resp2 = await fetch("https://api/files",
{
method: 'GET',
headers: {
"Authorization": "Bearer " + token,
"MemberID": membid,
'Content-Type': 'application/json;charset=UTF-8',
},
},
)
.then(resp2 => {
let respImg = resp2.json();
varImagePath = "should contain data.path where tag = 'govid'"
console.log('This is respImg values',respImg)
return respImg;
})
.catch(error => {
alert('Error in resp2 imgpath!' + error);
});
}
async getProfilePhoto() {
let token = await AsyncStorage.getItem(ACCESS_TOKEN);
this.getProfilePhotoPath(token);
let resp = await fetch("https://api/filepathtoimage", {
headers: {
"Authorization": "Bearer " + token,
"ImagePath": varImagePath,
}
})
let respBlob = await resp.blob();
let reader = new FileReader()
reader.readAsDataURL(respBlob)
reader.onload = () => {
this.setState({ imgsrc: reader.result })
}
}
console.log('This is respImg values',respImg) returns:
This is respImg values
Promise {_40: 0, _65: 0, _55: null, _72: null}
_40: 1
_65: 1
_55:
data: Array(2)
0: {recordid: "8888abc", accountno: "00-00-00000-00007-00", tag: "govid", filename: "gov_id.png", path: "C:\\MOBILEAPP\\governmentid/gov_id.png", …}
1: {recordid: "8888abc", accountno: "00-00-00000-00007-00", tag: "compid", filename: "compid.jpg", path: "C:\\MOBILEAPP\\compid/cid.jpg", …}
length: 2
__proto__: Array(0)
error_message: "Successfully retrieved."
is_success: true
requested_on: "12/18/2019 3:10:32 PM"
__proto__: Object
_72: null
__proto__: Object
How to I put value on varImagePath (in this example should be 'C:\MOBILEAPP\governmentid/gov_id.png')?
resp2.json() return a promise.
.then(resp2 => resp2.json())
.then(jsonObject => {
const data = jsonObject.data;
const record = data.find(item => item.tag === 'govid');
if (record) {
varImagePath = record.path;
}
})
Just use filter:
let filterString = 'govid';
const result = arr.filter(f => f.tag == filterString);
An example:
let arr = [
{
"recordid": "8888abc",
"accountno": "00-00-00000-00007-00",
"tag": "govid",
"filename": "gov_id.png",
"path": "C:\\MOBILEAPP\\governmentid/gov_id.png",
"ext": ".png",
"posted_dt": "12/11/2019 10:38:20 AM"
},
{
"recordid": "8888abc",
"accountno": "00-00-00000-00007-00",
"tag": "compid",
"filename": "compid.jpg",
"path": "C:\\MOBILEAPP\\compid/cid.jpg",
"ext": ".jpg",
"posted_dt": "12/11/2019 10:38:20 AM"
}
]
let filterString = 'govid';
const result = arr.filter(f => f.tag == filterString);
console.log(result);
UPDATE:
In your response:
then(resp2 => {
let respImg = resp2.json();
let arr = respImg.data;
let filterString = 'govid';
const result = arr.filter(f => f.tag == filterString);
return respImg;
})

ajax request doesn't execute when run test with marble diagrams

I use rxjs v6 and redux-observable v1
I have epic that send request to server and try to test epic like in doc. When I run test epic before send request emit 3 actions and it see on test result, but when epic comes to ajax call test finish. To mock request I use nock lib.
Epic:
import { ofType } from 'redux-observable'
import { of, merge, from } from 'rxjs'
import {
switchMap,
catchError
} from 'rxjs/operators'
import { apiRequest, handleAsyncError$ } from '../../async/lib'
import { actions as asyncActions } from '../../async'
import { LOADING_TYPES } from '../../async/constants'
import { actions as authActions } from '../reducer'
const setSignInLoading = (status) => of(asyncActions.setLoading({ type: LOADING_TYPES.signIn, status }))
const emitSignInPending = () => merge(
setSignInLoading(true),
of(authActions.signInPending())
)
const emitSignInSuccess = (payload) => merge(
setSignInLoading(false),
of(authActions.signInSuccess(payload))
)
const emitSignInFailed = (payload) => merge(
setSignInLoading(false),
handleAsyncError$({
action: authActions.signInFailure,
payload
})
)
// --------- ajax call -----------
const startSignIn = (payload) => apiRequest({
path: '/auth/signin/manager',
method: 'post',
body: payload
})
const mapSignInAction$ = ({ payload }) => merge(
// --------- emit 3 actions -----------
emitSignInPending(),
// --------- finish test -----------
startSignIn(payload)
.pipe(
switchMap((emitSignInSuccess)),
catchError(emitSignInFailed)
)
)
const signInEpic = action$ =>
action$
.pipe(
ofType(authActions.signIn),
switchMap(mapSignInAction$)
)
export default signInEpic
apiRequest:
import { get } from 'lodash'
import { throwError } from 'rxjs'
import { ajax } from 'rxjs/ajax'
import { map, catchError } from 'rxjs/operators'
import { API } from '../../../../config'
const apiRequest = ({ token, path, method, body }) => {
const settings = {
url: `${API}${path}`,
headers: { 'Content-Type': 'application/json' },
responseType: 'json',
crossDomain: true,
method,
body
}
if (token) {
settings.headers['Authorization'] = `Bearer: ${token}`
}
return ajax(settings)
.pipe(
catchError((request) => {
const error = get(request, 'response.error')
return throwError({ error, request })
}),
map(({ response }) => response)
)
}
export default apiRequest
Test:
nock(API)
.post('/auth/signin/manager')
.reply(200, response)
scheduler.run(({ hot, expectObservable }) => {
const source = hot('-a|', { a: authActions.signIn({ email: 'manager', password: '123123' }) })
const output$ = epic(source)
expectObservable(output$).toBe('-(bcde)', {
b: asyncAction.setLoading({ type: 'signIn', status: true }),
c: authActions.signInPending(),
d: asyncAction.setLoading({ type: 'signIn', status: false }),
e: authActions.signInSuccess(response)
})
})
Result:
Expected:
[{"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"status": true, "type": "signIn"}, "type": "[8] async/setLoading"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": undefined, "type": "[3] [2] auth/signIn/pending"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"status": false, "type": "signIn"}, "type": "[8] async/setLoading"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"data": {"token": "skldjf", "user": {"email": "manager", "id": 2, "passwordHash": "asdf", "passwordSalt": "6819c23dc7", "role": {"name": "user"}, "roleId": 1}}}, "type": "[4] [2] auth/signIn/success"}}}]
Received:
[{"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": {"status": true, "type": "signIn"}, "type": "[8] async/setLoading"}}}, {"frame": 1, "notification": {"error": undefined, "hasValue": true, "kind": "N", "value": {"error": false, "payload": undefined, "type": "[3] [2] auth/signIn/pending"}}}]
Ajax resolves as microtask so epic doesn't emit it sync, so marble diagrams can't handle it, I can't find how to do it with marble diagrams. So simple solutions is:
it('return token and user 2', async (done) => {
const response = {...}
nock(API)
.post('/auth/signin/manager')
.reply(200, response)
const source = authActions.signIn({ email: 'manager', password: '123123' })
const action$ = ActionsObservable.of(source)
epic(action$).pipe(toArray()).subscribe((actions) => {
expect(actions).toEqual([
asyncAction.setLoading({ type: 'signIn', status: true }),
authActions.signInPending(),
asyncAction.setLoading({ type: 'signIn', status: false }),
authActions.signInSuccess(response)
])
done()
})
})
Please write if you found how do it with marble diagrams.

Mongoose Update array in a document does not work as expected

I'm scratching my head since a couple day on how to update the content of an array with Mongoose.
Here is my schema to begin with:
const playedGameSchema = new Schema ({
created: Date,
updated: Date,
game: {
type: Schema.Types.ObjectId,
ref: 'game'
},
creator: {
id: {
type: Schema.Types.ObjectId,
ref: 'user'
},
score: Number
},
partners: [{
id: {
type: Schema.Types.ObjectId,
ref: 'user'
},
score: Number
}]
});
module.exports = mongoose.model('PlayedGame', playedGameSchema);
Basically, what I want to achieve is to, at the same time:
- Update the creator.score (successful with dot notation).
- Update the score key for each partner (unsuccessful).
Here is the result of a document created:
{
"creator": {
"id": "5b8544fa11235d9f02a9b4f1",
"score": 0
},
"_id": "5bb6375f5f68cc5c52bc93ae",
"game": "5b45080bb1806be939bfde03",
"partners": [
{
"_id": "5bb637605f68cc5cafbc93b0",
"id": "5b85497111235d677ba9b4f2",
"score": 0
},
{
"_id": "5bb637605f68ccc70ebc93af",
"id": "5b85497111235d677ba9b4f2",
"score": 0
}
],
"created": "2018-10-04T15:53:03.386Z",
"updated": "2018-10-04T15:53:03.386Z",
"__v": 0
}
As I said, I was able to change the score of the score creator by passing something like { "creator.score": 500 } as a second parameter, then I switch to trying to update the array.
Here is my lambda function to update the score for each partner:
export const update: Handler = (event: APIGatewayEvent, context: Context, cb: Callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const body = JSON.parse(event.body);
let partnersScore: object = {};
if(body.update.partners) {
body.update.partners.forEach((score, index) => {
const key = `partners.${index}.$.score`;
partnersScore = Object.assign(partnersScore, { [key]: score});
console.log(partnersScore);
});
}
connectToDatabase().then(() => {
console.log('connected', partnersScore)
PlayedGame.findByIdAndUpdate(body.id, { $set: { partners: partnersScore } },{ new: true})
.then(game => cb(null, {
statusCode: 200,
headers: defaultResponseHeader,
body: JSON.stringify(game)
}))
.catch(err => {
cb(null, {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: err
})});
});
}
Which passes a nice { 'partners.0.$.score': 500, 'partners.1.$.score': 1000 } to the $set.
Unfortunately, the result to my request is a partners array that contains only one empty object.
{
"creator": {
"id": "5b8544fa11235d9f02a9b4f1",
"score": 0
},
"_id": "5bb6375f5f68cc5c52bc93ae",
"game": "5b45080bb1806be939bfde03",
"partners": [
{
"_id": "5bb63775f6d99b7b76443741"
}
],
"created": "2018-10-04T15:53:03.386Z",
"updated": "2018-10-04T15:53:03.386Z",
"__v": 0
}
Can anyone guide me into updating the creator score and all partners score at the same time?
My thoughs about findOneAndUpdate method on a model is that it's better because it doesn't require the data to be changed outside of the BDD, but wanting to update array keys and another key seems very difficult.
Instead, I relied on a set/save logic, like this:
PlayedGame.findById(body.id)
.then(game => {
game.set('creator.score', update.creatorScore);
update.partners.forEach((score, index) => game.set(`partners.${index}.score`, score));
game.save()
.then(result => {
cb(null, {
statusCode: 200,
headers: defaultResponseHeader,
body: JSON.stringify(result)
})
})
.catch(err => {
cb(null, {
statusCode: err.statusCode || 500,
headers: { 'Content-Type': 'text/plain' },
body: JSON.stringify({ 'Update failed: ': err })
})});
})

Resources