In my react JS app, I make many API calls,
Rather than having to specify:
const BASE_URL = 'https://apiurlgoeshere.com/'
on every page, I'd rather have BASE_URL accessible throughout the entire application, so I can just do BASE_URL + API_CALL for example
If this is just adding BASE_URL, then this can be achieved by declaring it inside a constants.js file and exporting it from there. But then, that makes us do BASE_URL + "something" each time we make a network request which isn't really ideal either. Also there might be some scenarios where other configuration have to be shared, like say, a common header that has to be added to all the requests.
To solve this, most request libraries have in-build solutions. If we are choosing axios as the most popular one, we can create a instance like:
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
export default instance;
and import this everywhere the axios is going to be used like:
import axios from "./axios-instance";
assuming axios-instance.js is the file where the instance is created. Now you can skip adding the BASE_URL to every request as it is already provided in the instance.
If webpack is being used for code bundle, DefinePlugin can be used.
new webpack.DefinePlugin({
'BASE_URL': JSON.stringify('https://apiurlgoeshere.com/')
});
For gulp build, gulp-replace can be used.
.pipe(replace('BASE_URL', 'https://apiurlgoeshere.com/'))
I know it's been a while since I created this post - just wanted to go through what I've learnt really.
It's a great way to set a global config for Axios. I typically create a folder and create an api.js file within it which I use to make all of my API calls, this is great as it means you only have to specify headers / base URL / credentials etc once.
Here is a code example for a solution:
function apiCall (method, path, data) {
let url = "https://urltoyourapis.com/";
return new Promise((resolve, reject) => {
return Axios[method](url, {headers}, data).then(res => {
return resolve(res);
}).catch(err => {
return reject(err);
})
})
}
Now, whenever you want to make an API call you'd import this function into the file where you would like to make the API call and do the following:
apiCall("get", "account-info")
This will then make an API call to the endpoint "account-info" to get the information, you can either await and set the result to a variable or use .then .catch to handle the response.
Related
I want to achieve the same done here but in next.js.
Next.js provides methods to fetch data from a server and using them as props. I don't know whether you want to use it before rendering a page (like getServerSideProps) or when, for example, you click a button, but I suppose its the first case.
My personal preference when doing requests, is axios, so I will use it in this example:
export async function getServerSideProps({ req, res }) {
// Here is where we make the request
const result = await axios({
method: 'HEAD', // here is where we declare that we want to use the HEAD method
url: "your server url", // this is the url where we want to send the request
headers: {} // if you want to add custom headers, you can do it here
})
// Here we are logging the result of the request
console.log(result)
}
You can refer to the next.js documentation on data fetching and the axios documentation
Have a great day and I hope you succeed on your projects
I'm trying to create a bucket from the front end of a react app, once I work this out I will make the requests through the backend. I am passing in an options object inside of the useEffect hook and logging the result to the console. The headers are returning undefined on the environment variables I have passed in from a .env.I would like to know how do I pass in the headers from the .env or hard code for now? I aslo need to pass in scope into the headers bucket:create, bucket: read
Buckets.js
import React, { useEffect } from 'react'
import axios from 'axios'
const Buckets = () => {
useEffect(() => {
const options = {
method: 'POST',
url: 'https://developer.api.autodesk.com/authentication/v1/authenticate',
headers: {
ContentType: 'application/json',
Authorization: process.env.REACT_APP_FORGE_ACCESS_TOKEN,
client_id: process.env.REACT_APP_FORGE_CLIENT_ID,
client_secret: process.env.REACT_APP_FORGE_CLIENT_SECRET,
},
}
console.log(options)
}, [])
return <div>Buckets</div>
}
export default Buckets
There are a couple of problems with the code snippet:
first of all, you should never expose the client secret to the browser; implementing bucket creation on the server side is pretty straightforward
second, the process.env construct you use in your code is a Node.js feature, not something that's available in browser; that's most likely why the headers end up being empty
So with that, I would just suggest that you implement any of the Forge requests on the server side (for example, by following https://learnforge.autodesk.io), and then expose that functionality to your React frontend via a couple of endpoints.
EDIT: as mentioned in the comments, I'm working on "unofficial Forge SDK for Node.js", and that library does have an experimental support for browsers. Try something like this:
<script src="https://cdn.jsdelivr.net/npm/forge-server-utils/dist/browser/forge-server-utils.js"></script>
<script>
const client = new forge.DataManagementClient({ client_id: '...', client_secret: '...' });
client.listBuckets()
.then(buckets => { console.log('Buckets', buckets); })
.catch(err => { console.error('Could not get buckets', err); });
</script>
I've been trying to develop with the new Forge Dataviz NPM packages for a while but I've been facing errors. I'm currently just trying to load a Viewer (https://forge.autodesk.com/en/docs/dataviz/v1/reference/UI/Viewer/) but I think I'm doing something wrong. Still don't know what.
This is my React const :
const TestAutodesk= () => {
return (
<div>
<Viewer
env="AutodeskProduction"
docUrn="URN STRING"
getToken={async () => await fetch("https://developer.api.autodesk.com/authentication/v1/authenticate",requestOptions)
.then((res) => res.json())
.then((data) => data.access_token)}
></Viewer>
</div>
);
};
These are the requestOptions:
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("client_id", "ID");
urlencoded.append("client_secret", "SECRET");
urlencoded.append("grant_type", "client_credentials");
var requestOptions = {
method: "POST",
headers: myHeaders,
body: urlencoded,
redirect: "follow",
};
The final app is not going to use this as the auth, I'm going use a safe backend endpoint, this is just for trying to get the viewer loaded and the front end done. This is the error I get on the console:
I think the error is that is calling localhost:8080 but it should call an autodesk endpoint. Any idea on this? The Api reference / Dataviz example doesnt say anything about this.
The <Viewer> React component is pretty simple (https://github.com/Autodesk-Forge/forge-dataviz-iot-react-components/blob/main/client/components/Viewer.jsx), and shouldn't itself make any requests to localhost. Are you perhaps making those requests somewhere else in your application?
Regarding the getToken implementation, I'd suggest two things:
It's not a good practice to make these requests directly from the client-side code. This way, someone could potentially steal your Forge client ID and client secret. A better approach is to implement a custom endpoint in your own backend that generates the token with limited privileges, hiding the credentials from the client.
If you need to make the raw request to https://developer.api.autodesk.com/authentication/v1/authenticate, note that it requires 4 (not 3) parameters: client_id, client_secret, grant_type, and scopes.
I sent Axios Request in the React Component as always and succeeded.
server > routes > product.js
router.post("/removeImages", auth, (req, res) => {
req.body.images.map(imgPath => {
fs.unlink(imgPath, (err)=>{
if(err){
console.log(err);
}
console.log('Image removed successfully');
});
});
});
client > src > components > FileUpload.js
import Axios from 'axios';
function FileUpload(props) {
...
Axios.post('api/product/removeImages', { images: Images });
So, I copied the line(Axios.post('api/product/removeImages', { images: Images });) and used it in the child component. Then, the following error occurred:
POST http://localhost:3000/product/api/product/removeImages 404 (Not Found)
I thought it was an Axios bug, so I changed it to a fetch(), but I got the same result (404 Not Found). I do not know how hard-coded URL can change depending on the component. Maybe it was a React bug?
It looks like you're missing a starting / in the url. When not starting the url with /, it will be relative to whatever your path is currently.
Meaning if you're currently in localhost:3000/products, any requests to the relative path api/products/removeImages will resolve to localhost:3000/products/api/products/removeImages
A call to /api/products/removeImages, with the staring /, will only be relational to the base url, in this case localhost:3000, not the current path, thus result in locahost:3000/api/products/removeImages.
tl;dr: Add a prefixing / to your urls to resolve your relative path issue.
Additionally, as #ataravati mentioned in the comments, best practice is to also set a baseURL for axios.
I am a newbiew to ReactJs, need to know different ways by which we can include Headers in our service Url before making a call.
I am aware of how we used to make GET/POST Calls in angular Js after including headers...
Similarly want to know different ways to define headers in React Js, below is the sample of my component where i am making a service call.
There is a service Url which has few headers defined on Server side, how to include those headers on our side ...Sorry cant disclose the headers, please help me with some dummy headers data
componentDidMount(){
fetch('serviceURL')
.then(res=>res.json())
.then(items=>{
this.setState({
items : items.contactNumber
});
})
}
You can do something like this:
const request = new Request('https://example.com/some-url', {
headers: new Headers({
'Content-Type': 'text/plain'
})
});
fetch(request).then(() => { /* handle response */ });
You can find more information about using Headers in the docs.