I'm trying to grab data from my component state and than send that to a REST api. I make the axios post req in an on submit function, however I know this won't work in gatsby.My res.data is "This app works best with Javascript" when I make the request from the onSubmit function from Gatsby. I was wondering what was the best way I can make the post request from Gatsby so that I can pass in the data from the component's state. I have been looking into using this as my gatsby-node.js file however I'm not sure how I can get the component's state data in there so I can use it in the post req. Thanks.
onSubmit Function
//submits answers to backend
Submit = () => {
let {answers} = this.state
axios
.post("/done", answers)
.then(res => this.setState({results:res.data,resultsStatus:true}))
.catch(
err => console.log(err)
);
};
To fire the submit function I have a loading gif popup for 4 seconds and then I fire the submit function. Content request is that jsx being returned by the component
contentQuest = (
<div className = 'results-loading'>
Loading Results!
<img src={require('./images/loading.gif')} className='results-loading-gif'/>
</h2>
</div>
);
setTimeout(() => {
this.Submit()
},4000)
gatsby-node.js
// You can delete this file if you're not using it
const axios = require('axios');
const crypto = require('crypto');
exports.sourceNodes = async ({ boundActionCreators }) => {
const { createNode } = boundActionCreators;
// fetch raw data from the randomuser api
//Here I'm trying to change it to axios.post and grab component's state data
//not sure how to
const fetchRandomUser = () => axios.get(`https://randomuser.me/api/?results=500`);
// await for results
const res = await fetchRandomUser();
// map into these results and create nodes
res.data.results.map((user, i) => {
// Create your node object
const userNode = {
// Required fields
id: `${i}`,
parent: `__SOURCE__`,
internal: {
type: `RandomUser`, // name of the graphQL query --> allRandomUser {}
// contentDigest will be added just after
// but it is required
},
children: [],
// Other fields that you want to query with graphQl
gender: user.gender,
name: {
title: user.name.title,
first: user.name.first,
last: user.name.last,
},
picture: {
large: user.picture.large,
medium: user.picture.medium,
thumbnail: user.picture.thumbnail,
}
// etc...
}
// Get content digest of node. (Required field)
const contentDigest = crypto
.createHash(`md5`)
.update(JSON.stringify(userNode))
.digest(`hex`);
// add it to userNode
userNode.internal.contentDigest = contentDigest;
// Create node with the gatsby createNode() API
createNode(userNode);
});
return;
}
Edit:
I tried changing my post request to this
fetch('http://localhost:5000/api/done', {
method: 'POST',
body: JSON.stringify(answers),
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}) .then(res => {
return res.json()})
.then(res => console.log(res))
.catch(
err => {
console.log(err)}
);
};
Now I have this message in my console:
Access to fetch at 'http://localhost:5000/api//done' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
So it turns out I needed to include this in my server file.
app.use(function(req, res, next) {
res.header(`Access-Control-Allow-Origin`, `http://localhost:9000`)
res.header(`Access-Control-Allow-Credentials`, true)
res.header(
`Access-Control-Allow-Headers`,
`Origin, X-Requested-With, Content-Type, Accept`
)
next();
});
Related
I am using Next.js api route to handle a POST request then send a response back to the frontend. I have used Rapid API client extension to confirm there is a response being sent to the frontend. I just dont know how to handle it in the frontend.
Here is the code on the api route:
import clientPromise from "../../../config/mongodb";
export default async function userDetailsHandler(req, res) {
const body = req.body;
if (req.method == "POST") {
const client = await clientPromise;
const db = client.db("mood-board");
let emailQuery = await db
.collection("users")
.find({ email: body.email })
.limit(1)
.toArray();
let parsedData = JSON.parse(JSON.stringify(emailQuery));
res.status(200).json(parsedData)
console.log(parsedData)
} else if(req.method = "GET") {
}
}
In the following example, you use the fetch api to post the data which returns a promise. You can use then() which takes a callback function that you can use to operate on the data once that promise is returned.
Example:
useEffect(() => {
// POST request using fetch inside useEffect React hook
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React Hooks POST Request Example' })
};
fetch('https://reqres.in/api/posts', requestOptions)
.then(response => response.json())
.then(data => setPostId(data.id));
// empty dependency array means this effect will only run once (like componentDidMount in classes)
}, []);
When user drag and drop the Image, I need to call a method of the server to get the Media_id for that particluar image/video, in the response of that I am getting this ->
MAIN RESPONSE -->>
{
"status": 1,
"media": {"media_id": 27, "media_type": 1, "media_file_name": "a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png", "media_placeholder": null, "media_ext": "png"},
"upload":
{
"upload_url": "https://storage.googleapis.com/fnc-59aa2e6b-71552c9d-6441d628-951a8f6f/l.img/ori/a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png?Expires=1603388214&GoogleAccessId=12345678-compute%40developer.gserviceaccount.com&Signature=UNt8nS3%2BJYiS4AuYdZ7Z2fvfDZ0fAKf8bSZbeRlHyhqxb5i6xjpqnqgR7JYp9Q3FgJItcYr%2BHDL90WiUpbMQi%2B4s0XNW683CaSoUChkRMjj1AvkH%2Be0u8%2Fw5VVIMF9j52bTFePWISTLvwQ1RlEdNPNkrpbcamTsJFyBVi89%2BIpXArsVlhvDzK55Zvj%2Fvzh00GgdNrH%2BRog8Q%2BkGITE8bW%2FxRpQ30OdMZLjpLtp%2FNg5KVotHrx6Bet7vidKymiJQ9BbwCxTRGzBdAITr2rsKTMGZJzfvEKnIczsoiY91Zmc3hjGzUD9OxHGR%2BiRdN%2F2FbotOIVR48RE%2BoAdIGIEfKlw%3D%3D",
"file_name": "a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png",
"content_type": "image/png", "exp": "2020-10-22 17:36:54.447484"
}}
So, I need to hit this upload url which is coming from the response.Below is my file where I am hitting this as soon as user drop the image ->
UploadImage.js
await this.props.getFirstMediaId(postdata).then(res => {
if (res.value && res.value.status === 1) {
let media_idArr = this.state.media_id.concat(res.value.media.media_id)
this.setState({ media_id: media_idArr, mediaUrl: res.value.upload })
customStatus = 'done';
}
}) //First call to the server to get Media_id and the cloud **upload URL**
***** FOR THIS API RESPONSE, PLEASE SEE THE ABOVE MAIN RESPONSE *****
const getUploadParams = () => {
console.log(this.state.mediaUrl, ' -->>> this.state.mediaUrl')
if (this.state.mediaUrl !== null) {
console.log(' in get upload param.')
return this.props.postImageToCloud(this.state.mediaUrl).then(res => {
console.log(res, '===>> here is cloud res.')
})
.catch(err => {
console.log(' here is error cloud -->>> ', err)
})
}
}
Below is the file where the method actually call API ->
service.js
export const getFirstMediaId = (data) => {
return {
type: GET_FIRST_LISTING_MEDIA,
async payload() {
let response = await callAxios.post(SUBMIT_LISTING_FIRST_MEDIA, data);
return objectPath.get(response, 'data', []);
}
}
}
export const postImageToCloud = (url) => {
return {
type: PUT_MEDIA_TO_CLOUD,
async payload() {
let response = await axios.put(url.upload_url, {}, {
headers: {
'Content-Type': `${url.content_type}`
}
})
return objectPath.get(response, 'data', []);
}
}
}
So, the first call is success and I got the above MAIN RESPONSE but as soon as it completes, I call the cloud PUT request and got this CORS error ->
Access to XMLHttpRequest at 'https://storage.googleapis.com/fnc-59aa2e6b-71552c9d-6441d628-951a8f6f/l.img/ori/a9989aafcdf1482d8a0967a81b54b476_80a2d60394f15063bef4e44e1a4d83f3.png?Expires=1603388214&GoogleAccessId=123456789-compute%40developer.gserviceaccount.com&Signature=UNt8nS3%2BJYiS4AuYdZ7Z2fvfDZ0fAKf8bSZbeRlHyhqxb5i6xjpqnqgR7JYp9Q3FgJItcYr%2BHDL90WiUpbMQi%2B4s0XNW683CaSoUChkRMjj1AvkH%2Be0u8%2Fw5VVIMF9j52bTFePWISTLvwQ1RlEdNPNkrpbcamTsJFyBVi89%2BIpXArsVlhvDzK55Zvj%2Fvzh00GgdNrH%2BRog8Q%2BkGITE8bW%2FxRpQ30OdMZLjpLtp%2FNg5KVotHrx6Bet7vidKymiJQ9BbwCxTRGzBdAITr2rsKTMGZJzfvEKnIczsoiY91Zmc3hjGzUD9OxHGR%2BiRdN%2F2FbotOIVR48RE%2BoAdIGIEfKlw%3D%3D' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Please suggest me anything for make it working.
Thanks.
Finally after lot of efforts I came to know that I have to pass the file in the body of PUT request, here ->
let response = await axios.put(url.upload_url, { **file here** }, {
headers: {
'Content-Type': `${url.content_type}`
}
})
But I tried passing the image file object simple the html file object using formData and passing as it is, still getting the same error. Then i started using
react-dropzone and converted the image file into the string buffer as one of the example in React-dropzone. I am going to paste here that example maybe it can help anyone. See below ->
import React, {useCallback} from 'react'
import {useDropzone} from 'react-dropzone'
function MyDropzone() {
const onDrop = useCallback((acceptedFiles) => {
acceptedFiles.forEach((file) => {
const reader = new FileReader()
reader.onabort = () => console.log('file reading was aborted')
reader.onerror = () => console.log('file reading has failed')
reader.onload = () => {
// Do whatever you want with the file contents
const binaryStr = reader.result
console.log(binaryStr)
*****PASS THIS (binaryStr) AS IN THE BODY OF PUT TO AXIOS****
}
reader.readAsArrayBuffer(file)
})
}, [])
const {getRootProps, getInputProps} = useDropzone({onDrop})
return (
<div {...getRootProps()}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
</div>
)
}
This is one of the Official examples of React-Dropzone, So I just pass that string buffer obj and finally It worked, no CORS issue nothing.
The Google Storage API does simply not accept requests initiated from a browser in another domain, so you won't be able to achieve this.
You should not call the API from a client but from your backend. Here is the list of the suggested libraries: https://cloud.google.com/storage/docs/reference/libraries?hl=fr
Note that JavaScript in a browser environment is not suggested (only Node.js is)
I'm trying to make a POST request using axios to my firebase cloud-function on form submit in react app. But I get '500' error everytime I make a request with an html-page response This app works best with javascriot enabled.
Latest Update:
It looks like there is no issue with cloud function
code. Rather more of a react-component issue. I used Postman to send
the POST request with header prop Content-Type set to application/json
and sending body in raw format {"email": "example_email"} and got
expected response from the cloud function. But when sent the request from
react component above, I get an html file response saying the app
works best with javascript enabled
I've tried setting Content-Type to both Application/json and multipart/form-data as I suspected it to be an issue but still got no luck.
Following is my code for cloud function and react submit form:
Cloud Function
const functions = require('firebase-functions');
const cors = require('cors')({ origin: true })
const runThisFunc1 = require(./libs/runThisFunc1);
const runThisFunc2 = require(./libs/runThisFunc2);
exports.wizardFunc = functions.https.onRequest((request, response) => {
cors(request, response, () => {
let email = request.body.email;
try {
return runThisFunc1(email)
.then(data => {
console.log("Word Done by 1!");
return runThisFunc2(data);
})
.then(res => {
console.log("Word Done by 2!");
return response.status(200).send("Success");
})
.catch(err => {
console.error("Error: ", err.code);
return response.status(500).end();
});
}catch(err) {
return response.status(400).end();
}
});
});
React-Form-Component Snippet
import axios from 'axios'
...
handleSubmit = e => {
e.preventDefault()
const { email } = this.state
axios({
method: 'post',
url: `${process.env.REACT_APP_CLOUD_FUNCTION_ENDPOINT}`,
data: { email: email },
config: {
headers: {
'Content-Type': 'multipart/form-data'
}
}
})
.then(res => {
//do something with reponse here
})
.catch(error => {
console.error(error)
})
}
...
Is there something wrong I am doing in the code or the request config is wrong?
I tested with two apis for axios put.
for one api its working fine where as with another api it throws an error.
for one api its showing request as options eventhough I gave as put and I am seeing 403 forbidden error
for this api i am facing the issue 'http:///sports/sportsId',
I debugged but still I am not able to find the issue.
is it a back-end issue
can you tell me how to fix it, providing my code snippet below
savesports = () => {
console.log("savesports---->");
console.log(this.state.sports);
let savesports = this.state.sports;
savesports.updatedBy = 'xxx';
savesports.priceRuleDescription = "test description";
let data = {
name: "yyyy",
email: "sda#gmail.com",
phone: "2321313"
};
axios
.put("https://jsonplaceholder.typicode.com/users/1", data)
.then(r => console.log("dada", r));
console.log(JSON.stringify(savesports));
axios
.put(
'http:///sports/sportsId',
savesports
// { headers: { 'Content-Type': 'application/json' } }
)
.then(r => console.log(r))
.catch(e => console.log(e));
//this.toggleDrawer("right", false);
this.setState({ right: false });
this.setState({ snackBarOpen: true });
setTimeout(() => {
this.setState({ snackBarOpen: false });
}, 6000)
};
1. Check if URL is right
I would first check if the URL is right.
Try changing http:///sports/sportsId to http://sports/sportsId if that's actually the URL you are requesting to.
2. Avoid name confusion
Both the method name and the put data variable name are the same (savesports). I would change the put data variable name to something meaningful like
let sportsData = this.state.sports;
sportsData.updatedBy = 'xxx';
sportsData.priceRuleDescription = 'test description';
3. Check authentication
403 might also be to auth error. I would check if the endpoint requires any authentication token or headers.
API requests are failing because the URL generated by Axios is incorrect due to my config. I know what the request url is suppose to look like, so I want to see the request url Axios generates.
I can point Axios to my local server and see the requests there, but I want to debug this on the client. I want to play with the config, and see how the requests change. Is there a way to output the request url from Axios before or after sending?
// param format
{ address: 'Vancouver', key: GOOGLE_API_KEY }
// Geocode sample
https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&key=YOUR_API_KEY
_request = async (...args) => {
const { outputFormat, params } = args
const instance = axios.create({
baseURL: `https://maps.googleapis.com`,
})
const response = await instance.get('/maps/api/geocode/${outputFormat}?', {
params,
})
// I want to see the url generated by Axios so I can debug the issue
console.log(response)
}
I am within the Expo, React Native environment.
Working example using fetch:
const url = `https://maps.googleapis.com/maps/api/geocode/json?address=vancouver&key=${GOOGLE_API_KEY}`
fetch(url)
.then((response) => response.json())
.then((data) => {
console.log(data)
})
.catch(function(error) {
console.log(error)
})
Solution used:
_request = async (obj) => {
const { outputFormat, params } = obj
const instance = axios.create({
baseURL: `https://maps.googleapis.com`,
})
instance.interceptors.request.use(function (config) {
console.log(config)
return config
}, function (error) {
return Promise.reject(error)
})
const response = await instance.get(`/maps/api/geocode/${outputFormat}`, {
params,
})
}
You can turn on debug mode and look at the network tab as mentioned in the other answer, or you can intercept axios and console.log or do whatever you want with the request before it's sent:
axios.interceptors.request.use(function (config) {
// Do something before request is sent
console.log(config)
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
You can just use axios#getUri([config]) (source) to perform the same logic as the request. It merges the configurations (e.g. the given config and the instance configuration), merges the url with the baseURL, and appends any params using the paramSerializer.