I am sending a GET request inside an OpenShift pod to a backend application. In the console of the openshift pod I can run the following command succesfully:
wget -qO- --no-check-certificate \
--header 'Accept: */*' \
--header 'Authorization: Basic <base64 encoded auth>' \
https://my-url.nl:8221/path/to/my/resource/organisations
I can also call the API endpoint from postman without issue (from a different server).
However, when I run the following fetch I get a timeout.
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
const credentials = Buffer.from(
`USERNAME:PASSWORD`
).toString('base64');
fetch(
'https://my-url.nl:8221/path/to/my/resource/organisations',
{
method: 'GET',
headers: {
Authorization: `Basic ${credentials}`,
Accept: '*/*',
},
}
).then((data) => {
console.log(data.json());
}).catch((reason) => {
console.log(reason);
});
I get the following error after a long wait
GET https://my-url.nl:8221/path/to/my/resource/organisations net::ERR_CONNECTION_TIMED_OUT
Uncaught (in promise) TypeError: Failed to fetch
Both the preflight and actual API call fail.
Am I forgetting something simple? Does this have to do with CORS? Or something with skipping the certificate validation? What kind of API call would return a timeout rather than a failed (400/500) response.
It's simply not going to work if you're doing it from the browser, as seen in the photos.
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
These two lines do nothing in the browser. They only work in a NodeJS environment.
The only way to make it work is to change the backend endpoint, to a valid SSL cert (not self-signed). The easiest way to do that is probably cloudflare.
EDIT: I suspect you're compiling this from Node via react, vue, etc. In that case, it absolutely won't work because process.env is setting a system environment variable. Browsers don't have environment variables, so this isn't going to work, those 2 lines will do nothing.
Thank you for the comments & answers to my post. It made me question how I was calling the endpoint. I am working with NextJs (React framework). This allows you to perform API calls, either client side or server side. I was performing these calls client side rather than server side (which won't work). The solution is to use the NextJs GetServerSideProps function.
My full working solution for anyone interested:
import { PageLayoutWithSideMenu } from '#pcss-cargonaut/ui-lib';
import NextLink from 'next/link';
import { GetServerSideProps } from 'next';
type Organisation = {
accountNumber: number;
accountSequenceNumber: number;
name: string;
role: string;
};
type Organisations = Organisation[];
export const getServerSideProps: GetServerSideProps = async () => {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
const credentials = Buffer.from(
`USERNAME:PASSWORD`
).toString('base64');
const res = await fetch(
'https://my-url.nl:8221/path/to/my/resource/organisations',
{
method: 'GET',
headers: {
Authorization: `Basic ${credentials}`,
Accept: '*/*',
},
}
);
const organisations: Organisations = await res.json();
return { props: { organisations } };
};
const Organizations = ({ organisations }: { organisations: Organisations }) => {
console.log(organisations);
return (
<PageLayoutWithSideMenu>
...
</PageLayoutWithSideMenu>
);
};
export default Organizations;
Fetch returns a promise that resolves with a Response object and the response.json() returns, in turn, another promise that resolves with the result of parsing the response body text as JSON.
So, you have to add another .then() after the first one.
A general example below:
fetch('http://example.com/movies.json')
.then(response => response.json())
.then(data => console.log(data));
Related
I'm trying to run a simple example consuming the list of page slugs from WordPress REST API, but I'm facing a very strange behavior.
I have an async function getPageList() that simply calls the WP API using fetch.
const getPages = async (path) => {
return await fetch(process.env.NEXT_PUBLIC_WP_API_URL + "/pages?_fields=slug", {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
}
Running through the browser, I have no issues calling this method and getting the results:
export default function Example() {
useEffect(() => {
getPageList().then(pages => console.log(pages))
}, []); // OK
return null
}
However if I try to execute the same call from the server, inside getStaticProps, I receive the error FetchError: request to http://localhost:8000/wp-json/wp/v2/pages?_fields=slug failed, reason: connect ECONNREFUSED 127.0.0.1:8000
This is the code snippet:
export async function getStaticProps() {
const pages = await getPageList()
//(....)
}
If I query this URL using Postman or just copy and paste in the browser, it works seamlessly too.
Any ideas on what's going on?
I'm using create-next-app, Node 16.13.0, Wordpress 5.8.2, PHP 7.4.3 running using local development server (php -S localhost:8000)
Thank you in advance!
This was related to how I was initiating my PHP built-in server. Changing it to php -S 127.0.0.1:8000 instead of localhost:8000 fixed the problem.
Im trying to make a discord bot where if you type -cr into the chat, it takes the Arguments of the user (Being the Clash Royale Player's player tag) and would then use the package node-fetch to receive data with my specified endpoint. I am constantly running into the error of { reason: 'accessDenied', message: 'Invalid authorization' }. Im rather new to this stuff, especially API's, but im hoping to access certain data which I can decide later on (Which I know how to do). My code is :
const fetch = require('node-fetch')
module.exports = {
name: 'clash',
aliases: ['cr', 'clashroyale'],
category: 'This',
utilisation: '{prefix}clash',
async execute(client, message) {
var msgArgs = message.content.slice(this.name.length + 1)
var endpoint = `/players/${msgArgs}`
var url = `https://api.clashroyale.com/v1`
var token = `hidingmytoken`
fetch(url + endpoint, {
method: 'POST',
headers: {
"Authorization": token
}
}).then(data => data.json()).then(json => {
console.log(json)
})
},
};
The message parts with msgArgs and discord sides all work but fetching that clash Royale API is a big hurdle for me. The API for Clash Royale can be found here https://developer.clashroyale.com/#/documentation and Im just generally stuck on this whole concept. Im using version 2.6.6 of node-fetch so I can use the require() method which should work if that does matter. In general, how can I pass my token properly to receive that API data?
Since the Clash Royale API uses bearer authentication, you need to specify that it will be a bearer token.
headers: {
'Authorization': `Bearer ${token}`
}
I've implemented the following functionality. The code is written in GO but you can copy the logic and translate into your language.
The library have the following functionality:
Login
Token generation
Token list
Token delete
https://github.com/alessiosavi/GoClashRoyale/blob/master/api/auth.go
I have a button which sends an API bug report, however I recently moved it from Main.js into into its own class, and suddenly I receive CORS errors among others whenever I attempt to use it. I've done some research but I can't understand why this would be triggered simply by moving the function into its own class, looking for guidance as to why this behaviour might happen and how to avoid it.
Errors:
Uncaught (in promise) TypeError: response.json is not a function
Access to fetch at 'exampleUrl' from origin 'http://localhost:4567' has been blocked by CORS policy: Request header field token is not allowed by Access-Control-Allow-Headers in preflight response.
Uncaught (in promise) TypeError: Failed to fetch
$("#bugForm").submit((e) => {
e.preventDefault()
const input = document.getElementById('nameInput');
// logic here
const bugInfo = {
info: "Hello"
}
Logger.logInfo(bugInfo).then(console.log('print'))
})
});
Logger.js
class Logger {
constructor(settings) {
// getting the settings here and assigning it to the constructor variable
this.settings = settings;
}
static async logInfo(data = {}) {
console.log('Hello!')
const url = 'https://www.pivotaltracker.com/services/v5/projects/2530461/stories'
const response = fetch(url, {
method: 'POST',
headers: {
"Token": `${metadata.settings.token}}`,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
return response.json();
}
}
const metadata = {
settings: "Hello"
}
const logger = new Logger(metadata.settings);
Code before the move into new class:
async function reportBug(data = {}) {
const url = 'urlexample'
const response = await fetch(url, {
method: 'POST',
headers: {
"X-TrackerToken": `${metadata.settings.token}`,
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
return response.json();
}
enter code here
No, this has most likely nothing to do with moving your function to another class.
But first of all, you are using fetch wrong
const response = fetch(url, { ...});
returns a promise. You have to wait until it resolves or rejects, until you can try accessing its body. Ie, you can't just do
return response.json()
because a Promise doesn't have a method json() (as the first error tells you). You have to either use .then(...).catch(...) or await. For instance
return fetch(...)
.then(response => {
if (response.ok) //check if httpstatus is 2xx
return response.json();
throw new Error(`status ${response.status`);
}
But be aware that this will also return a Promise (as response.json() is again async and returns a promise), which you have to wait for. And (at some) point you have to .catch() the errors from rejected promises (that's what the third error is telling you, your fetch ran into some error you are not catching) Grab one of the thousands of tutorials about async programming and rework your code.
The second error is telling you, that the answer from that server is missing a specific header definition from the Access-Control-Allowed-Headers header. (and that's most likely causing your fetch to fail). Ie you are sending a Token header to the server which is not allowed by the server. So, if you said it worked before moving the code, you probably didn't have that header before and added it shortly after moving the code. Although I'm not really sure, how that incorrect async programming would have worked ...
What else should I try?
I'm currently sending a request to the DeepL API in axios, but I'm getting a 403 response due to a CORS issue.
And tried to set the option using querystring as shown here, but it didn't work. https://github.com/funkyremi/deepl/blob/master/index.ts
Also, using the library at the URL above returns 403.
Furthermore, there is no origin setting in the account settings of DeepL.
I tried using 'Content-Type': 'application/x-www-form-urlencoded' for axios headers: {}, and I also tried setting options for params: { } and not using querystring, but they didn't work.
import axios from 'axios'
import querystring from 'querystring';
export const translateDeepL = async() => {
const options = {
"auth_key": process.env.DEEPL_AUTH_KEY,
"text": 'everyday is birthday.',
"target_lang": 'JA',
};
const url = "https://api-free.deepl.com/v2/translate";
const data = await axios.post(url, querystring.stringify(options)).then(r => r);
console.log(data);
}
VM3451:1 POST https://api-free.deepl.com/v2/translate 403
the request use https with ngrok did't work also.
I also tried the GET method for "https://api-free.deepl.com/v2/usage" but got the same result.
It is definitely api-free.deepl.com since I am using the free plan.
By the way, the above code is executed as a component in React.
the DeepL API does not support being used directly from within browser-based apps. The API Key is not supposed to be shared publicly as well and should always be kept secret.
The best approach is to use a backend proxy for the API Calls.
I was encountering this same issue and couldn't find an answer. This API just didn't seem to want to talk to me via a browser.
My 'solution' was to set up an API proxy in node.
It works fine fetching from a back-end + now I can add some rate limiting etc
C.J on coding garden can explain this way better than I ever can.
You might be being blocked because of sending a request from http (your localhost) to https, try using the proxy axios config, like
const response = await axios
.get("https://api-free.deepl.com/v2/translate", {
params: {
auth_key: x,
text: y,
target_lang: z
},
proxy: {
host: "localhost",
port: 8080
}
});
return response;
};
i've been trying to fetch some data from the riot's api, and I have a problem:
This is the important part of the code:
const getUsuario = async (name) => {
const resp = await fetch(`${APIRUL}${name}${apikey}`, {
method: 'GET',
mode: 'no-cors',
headers: {
"Content-Type": "application/json",
},
});
const { data } = await resp.json();
return data;
};
getUsuario("user-name");
If i put mode: cors. I have a problem with CORS, but if I have as the example above, it shows up this:
champions.js:15 Uncaught (in promise) SyntaxError: Unexpected end of input
at getUsuario (champions.js:15)
This is the line 15:
const { data } = await resp.json();
I found a similar error to what you are seeing here: fetch() unexpected end of input
Try printing the response before turning it to json and see if you see type opaque. This is specific to fetch requests made with mode no-cors. There seems to be a lot of restrictions to what you can do with this kind of response.
Updated: The RiotGames api server does not return the CORS headers for a reason. Most likely they don't want you to access their API directly from the browser. You need to have a backend make those api requests for you which can then forward the responses to your frontend.