React Autodesk Forge Create Buckets - reactjs

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>

Related

NextJs CORS issue

I have a Next.js app hosted on Vercel at www.example.com, which needs to communicate with a backend .NET Core Web API hosted on a different server at api.example.com.
The .NET core web api has been configured to allow CORS but my Next.js keeps complaining that data cannot be displayed when I use AXIOS to fetch data because the response lacks allow-cors headers:
Access to XMLHttpRequest at 'https://api.example.com' from origin 'http://www.example.com' 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
It works fine when I run it locally using npm run dev, but doesn't work when I build it and then run npm run start
Does anyone know how to fix the cors issue in production?
I found a solution here:
Basically, I just need to add a next.config.js file in the root directory and add the following:
// next.config.js
module.exports = {
async rewrites() {
return [
{
source: '/api/:path*',
destination: 'https://api.example.com/:path*',
},
]
},
};
if you want to use the cors library in nextjs, I created a library for it is nextjs-cors.
https://www.npmjs.com/nextjs-cors
https://github.com/yonycalsin/nextjs-cors
pages/api/whoami.{ts,js}
import NextCors from 'nextjs-cors';
async function handler(req, res) {
// Run the cors middleware
// nextjs-cors uses the cors package, so we invite you to check the documentation https://github.com/expressjs/cors
await NextCors(req, res, {
// Options
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE'],
origin: '*',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
});
// Rest of the API logic
res.json({ message: 'Hello NextJs Cors!' });
}
it was a problem in the server not accepting OPTIONS requests, because routes were declared as GET::something or POST:: something, so the preflight couldn't pass and the POST request was decliend, hope this will help another people to prevent hours of googling, so in my case (Node.js + Express.js) i had to add this to my server.js
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
if (req.method == "OPTIONS") {
res.header("Access-Control-Allow-Methods", "PUT, POST, PATCH, DELETE, GET");
return res.status(200).json({});
}
next();
});
I had a similar issue, I was making the call from this page:
pages/page1.js
export default async function page1() {
const data = await axios.post('https://www.dominio.com/xxx' , {param: 1}, headers)
}
But the solution is to make axios calls to a local API file inside "pages/api" directory, and this local API file, will handle the request to the external webserver. This avoid the CORS issue.
pages/page1.js
export default async function page1() {
const data = await axios.post('/api/get_page1_data', {param: 1} )
}
pages/api/get_page1_data.js
export default async function handler(req, res) {
try{
const data = await axios.post('https://www.dominio.com/xxx' , {param: req.body.param}, headers)
res.status(200).json(data)
} catch (error) {
console.error(error)
return res.status(error.status || 500).end(error.message)
}
Do an extra check if your base URL is correct that was my issue
In my case, the preflight request was failing due to an agressive HTTP method filter.
Make sure that you specify
// Preflight Check:
if (req.method == "OPTIONS") {
res.setHeader("Allow", "POST");
return res.status(202).json({});
}
// Allow only POST Methods
if (req.method !== "POST") {
res.setHeader("Allow", "POST");
return res.status(405).json({ error: `Method ${req.method} Not Allowed` });
}
You can allow all methods with https://vercel.com/support/articles/how-to-enable-cors#enabling-cors-in-a-next.js-app, but make sure that each endpoint returns a 2XX status code for the OPTIONS HTTP method.
Please make sure it is CORS and is not something else. For example, in my case I was getting a 400 response. Please look on the Response tab of that request for information.
after hours of googleing i found the solution on the next-docs itself!!!
see the following repository on github
API Routes Example with CORS
https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors
I had this issue taking a SoloLearn NestJS course and it was resolved by adding the line: app.enableCors() in main.ts file on the root folder in the NESTJs Project.
The file was like this:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
await app.listen(3000);
}
bootstrap();
I have Next.js application that has graphql and Apollo Client setup (apollo version : 3.5.10). In order to make a query inside any component you have to use "client" variable that Apollo Client provide. You need to have apollo-client.js file in your project root so that Apollo Client can use it inside any component for query. Inside any component when you trying to make a query like: client.query(...), with these settings of apollo-client file it will throw "cors" error. However you can fix this by adding headers property inside apollo-client file.
This is OLD Settings:
apollo-client.js (old)
import { ApolloClient, InMemoryCache } from '#apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
export default client;
This is NEW Settings:
apollo-client.js (new)
import { ApolloClient, InMemoryCache } from '#apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
headers: {
fetchOptions: {
mode: 'no-cors',
},
},
});
export default client;
By doing this, you won't get any "cors" error while doing query inside any component.

why does react.js when upload file return cors

const formData = new FormData();
formData.append("CustomerName", this.state.customerName);
formData.append("Email", this.state.email);
formData.append("Phone", this.state.phone);
formData.append("PageNumber", this.state.pagesNumber);
formData.append("Notes", this.state.notes);
formData.append("WritingConversionTypeId", this.state.writingConversionTypeId);
formData.append("WritingDocumentTypeId", this.state.writingDocumentTypeId);
formData.append("WritingTimePeriodId", this.state.writingTimePeriodId);
formData.append("files", 'null');
writingRequest.postwritingRequest(formData).then((res) => {
console.log(res);
});
when attach to headrs form data it return CORS
i'm using react.js and server side ASP.NET Core3.1...
and it works when removing the (Content-Type: multipart/form-data) from headers
it works in swagger
enter image description here
in
at React Service to Call Api
import http from "../../config/http";
import endPoints from "../endPoints";
const writingRequestUrl = endPoints.WRITING_REQUEST_ENDPOINT;
export default {
postwritingRequest(writingRequest) {
return http
.post(
writingRequestUrl,
writingRequest
, {
headers: {
'enctype': 'multipart/form-data',
"Content-Type": "multipart/form-data"
},
}
)
.then((res) => {
return res;
});
},
};
In StartUp
At ASP.NET CORE
ConfigureServices
//Enable CROS To allow access to the resource
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
}));
In Configure
app.UseCors("MyPolicy");
CORS has nothing to do with react, your browser prevents the call as the client runs on a different domain than your server. On production this is usually not an issue, since both are typically running on the same domain.
If you want to avoid CORS in development, the Create React App bundle comes with a proxy server, that appends the CORS header to all HTTP requests, as described in the documentation.
Simply add the URL to your api to your package.json like so:
"proxy": "www.url-to-your-api.com"
Then make sure to run all requests from your react app against absolute links, so instead of calling www.url-to-your-api.com/api/ you should simply use /api/, this will use the proxy in development and the regular route in production.

POST Request to Azure DevOps Rest API with Reactjs

So far I've been able to configure a method in C# that is able to hardcode a new repository in Azure DevOps, but my real goal is to create a user interface that allows the user to specify the request body which consists of the following:
name: 'nameOfRepository',
project: {
id: 'projectId'
}
The user will fill out the first input field with the desired name of the new repository. The second input field should use a GET Request that displays all available projects in your organization in a dropdown list.
I'm also using .NET Core 3.0 and believe this probably has to be done with an API controller as well, but I am not certain.
I have little to no experience with React and have no idea how and where I'm going to specify the request body and personal access token to create the repository. I would appreciate an explanation of how this works and would also appreciate a solution that could guide me in the right direction.
Azure DevOps Rest API Documentation will give you access to the platform. If you are decided to develop totally in React js. I would like to suggest to take a starter kit, mostly will cover all your basic setup to React.
Follow the below steps to get an idea of how you can achieve with react js
Need to set up OAuth in azure deops. The below link will give an idea. In the callback page, you need to store access token store
https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/oauth?view=azure-devops. If you have personal auth token this is not required
Get all list of repositories using fetch or Axios API
Example with Axios:
const headers = {
'Content-Type': 'application/json',
'Authorization': 'bearer token' or 'basic personalaccesstoken'
}
axios.get('https://dev.azure.com/{organization}/{project}/_apis/git/repositories', {
headers: headers,
params: {
'api-version':'5.1'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Use react form to capture the input value and on submit of form, validate against the repositories, if it is new call the Axios or fetch post method to create a new repository
Example with Axios
const headers = {
'Content-Type': 'application/json',
'Authorization': 'bearer token'
}
const data = {
name: ''
parentRepository: {id: '', ....}
project: {id: '', ...}
}
axios.post('https://dev.azure.com/{organization}/{project}/_apis/git/repositories', JSON.stringify(data),
{
headers: headers,
params: {
'api-version':'5.1'
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Similarly, you can access all the API's mentioned REST API documentation of Microsoft. link

How can I access Google Fit data without logging in

I have a web page I am working on, I am wanting to use gapi to access my steps for the day. I do not want to log in every time, I want the page to log in automatically in the background, oAuth2 is required I believe but I can not get any further.
Based on code I've found online and using React with Hooks, I added ts ignore because it could not resolve gapi.
The issue I am having is that I get Login Required error
I've tried using Axios and doing it by API_KEY only. My knowledge on API's is growing but I thought just to access the data an API key would be enough providing I had registered the key in the API tools.
React.useEffect(() => {
const start = () => {
// 2. Initialize the JavaScript client library.
// #ts-ignore
gapi.client.init({
'apiKey': '<API_KEY>',
// clientId and scope are optional if auth is not required.
'clientId': '<CLIENT_ID>.apps.googleusercontent.com',
}).then(function() {
// 3. Initialize and make the API request.
// #ts-ignore
return gapi.client.request({
'path': 'https://www.googleapis.com/fitness/v1/users/<MY_GMAIL_ADDRESS>/dataset:aggregate',
'method': 'POST',
'body': {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 },
"startTimeMillis": 1567983600000,
"endTimeMillis": 1568057160150
},
})
}).then(function(response) {
console.log(response.result);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
};
// #ts-ignore
gapi.load('client', start);
}, []);
I just want to be able to return my steps in a JSON object preferably with Axios, if not using the gapi JS library using my React Application. Nothing fancy.
I appreciate this may not be possible but the docs and other questions on stack overflow just are not working for me and no one can answer me.

How do I create a globally accessible variable in React JS

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.

Resources