ReactJS - NodeJS - Issue Connecting to Graphql On AWS Lambda - node.js

I have a nodejs lambda function deployed on aws which exposes a lambda endpoint via API Gateway.
The endpoint is here and allows you to access the graphiql endpoint.
I have been trying to call this from my react code but I am getting the following error response
{"message":"Missing Authentication Token"}
And the following console warning
Failed to load https://z8zch5bp3m.execute-api.us-east-1.amazonaws.com/test: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have enabled cors in the API gateway but still getting this error.
My simple react code is as follows
import React, { Component } from 'react';
import { gql } from 'apollo-boost';
import { Query } from 'react-apollo';
const ADD_NUMBERS = gql`
query {
addNumbers(number1:1, number2:55) {
add
}
}
`
const App = () => (
<Query query={ADD_NUMBERS}>
{({ loading, error, data }) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error :(</div>;
return (
<div>Data: {data}</div>
)
}}
</Query>
)
export default App;
The nodejs code for my lambda function is located here
Please let me know if I need to do anything to get this lambda call working.

Looking into your code did not tell me much. I would advise you to take a look into those topics:
Missing Authentication Token is also returned when you make an HTTP call with the wrong method (say you want to POST, but you PUT);
Look into Lambda Proxy Integration. When using Lambda Proxy Integration you can specify headers in your response. There you can make sure to allow Cross-Origin-Resource-Sharing.
Hope this helps.

Got this working by recreating my api gateway endpoints with cors enabled from the start and it worked as expected

Related

Page not changing onClick using useNavigate in React?

I have a very basic UI for a login page:
Upon clicking the LOGIN button, the following methods gets called:
async function loginPatient(){
let item ={username:userName, password};
let result = await fetch("http://localhost:8000/users/login",{
method:'POST',
headers:{
"Content-Type":"application/json",
"Accept":"application/json"
},
body: JSON.stringify(item)
});
alert(result);
alert("breakpoint")
result = await result.json();
localStorage.setItem("user-info",JSON.stringify(result));
nav('/patient')
}
At this point I simply want it to change the page when the button is clicked. My API returns the following information from the database:
To test I did console.log("hello world") in the first line of the function and it works
However, If I run console.log("hello world") after the let result = await fetch(...) part it does not work. How can I test this to see why it's not working ?
Here are the errors from the console:
I did not write the API and do not know how Node works yet, I am just doing the front end for this
The issue is code is never reaching after fetch line, basically request is failing, the error on console is saying the due to CORS issue, the request failed, and in your loginPatient function, you have not handled the failed case, if you just wrap your fetch call inside try/catch block, you will see your code will fall into fail block, as api failed.
You need to enable CORS on your server or backend, Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.
You can read more about cors at:
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Looks like your client is on some other domain or port(if your are developing locally) than your server. You need to enable CORS permission for your client url.
And if you are using express for your backend, you can check the following url to enable cors.
https://expressjs.com/en/resources/middleware/cors.html
And last thing why Postman is getting success response, because it is by passing this cors check, as Postman is making request from it's server to your direct server instead of browser.
First initialize you navigation variable as follows
const navigate =useNavigate()
then navigate to you specific route by returning you navigation variable as follows.
return navigation("/");
Happy Coding!

HTTP request working from Postman and Node but not React

There are a few questions similar to this on Stack Overflow, and none of the proposed solutions worked, so I'll walk through the case and what I've tried.
I have a server application hosted on Cloud Run, which can only be accessed with the appropriate Bearer token in the request Authorization header. I've tried accessing it via Postman and an Axios request from a local Nodejs server, with the Authorization header, and it worked fine. With React (create-react-app specifically), I get the following error: Access to XMLHttpRequest at 'https://myserver-lhp5a9xp5a-ue.a.run.app/api/rules' from origin 'http://localhost:3000' 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.
On the server side, I get the 403 error that Cloud Run gives when the incorrect Authorization token is passed. Also, when I allow unauthenticated access from the Cloud Run side (so remove the need for an Authorization header), the request works fine, so it looks like this is indeed an issue with the Authorization header and not CORS.
In addition, I'm handling CORS on the server side. Here's my server-side code:
var express = require('express');
var router = express.Router();
const cors = require('cors');
router.options('/api/rules', cors());
router.get('/api/rules', cors(), (req, res, next) => {
res.status(200).send()
});
Here's my React code:
const axiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL
});
const buttonClickHandler = async (event) => {
const resp = await axiosInstance.get('/api/rules'
, {
headers: {
'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsImtpZ...' // I used this token within the same minute when trying the request via Postman or from my Nodejs app, so a token expiry isn't the issue.
}
}
)
console.log(resp.data)
}
Here's what I tried so far:
Using fetch instead of axios - same error
Using the same token, within the same 5 seconds, to send the request from Postman or a Nodejs server - it worked fine.
Using an axios interceptor to set the Authorization - same error
Removing the single quotes around Authorization - same error
Sending the request to my Nodejs server instead and doing a console.log of the header to make sure the Authorization token is being passed correctly (it is)
Not using an an axios instance but spelling out the full URL in the request - same error
Trying a different endpoint on my Cloud Run server - same error
Deploying my React app to be served from a https endpoint and sending the request from there - same error
Adding Accept: '*/*' to the headers
Adding 'Accept': '*/*' to the headers
Adding 'Content-Type': 'application/json' to the headers
All combinations of the three above points
I found the answer after some digging, thanks #aniket-kolekar for pointing me in the right direction.
When Postman or a Nodejs server query an endpoint like GET, POST, PUT, DELETE, they send the call without checking the OPTIONS first. Create-React-App does.
The service I was querying is hosted on Cloud Run and doesn't allow unauthenticated invocations. So while I was including the authorization header to make my GET call, it wasn't being included in the pre-flight OPTIONS call. In fact, CORS prevents auth headers from being included in an OPTIONS call.
A Cloud Run PM replied in this post that this is a known issue with Cloud Run. The way I'll get around it for now is to host two services on Cloud Run - one that doesn't require authentication, and effectively acts as a proxy server to route calls from the client service to the shielded server service.
TLDR;
CORS is a mechanism built into the web browser. It’s not a UI code issue.
To fix CORS problems, you need to make changes on the API (server) side.
Here is the behind the scenes working:
Browser: Sends OPTIONS call to check the server type and getting the headers before sending any new request to the API endpoint. Where it checks for Access-Control-Allow-Origin. Taking this into account Access-Control-Allow-Origin header just specifies which all CROSS ORIGINS are allowed, although by default browser will only allow the same origin.
Postman: Sends direct GET, POST, PUT, DELETE etc. request without checking what type of server is and getting the header Access-Control-Allow-Origin by using OPTIONS call to the server.
You will have to configure Access-Control-Allow-Origin header in your server to resolve the CORS issue.

How to use fetch to fetch data from AWS RDS in a react application?

I'm learning Node + React. In my Node + React application, I have the following component FetchData.js to fetch data from localhost:
import React from 'react';
class FetchData extends React.Component {
static async getData() {
let response = await fetch('http://localhost:4000/my-project');
let body = await response.json();
return body
}
}
export default FetchData;
I could see the json objects by typing localhost:4000 in the browser.
Now I'm hosting the data in AWS RDS. I have an endpoint like this:
my-project.abc12345def.eu-west-2.rds.amazonaws.com:3306
How can I fetch data from the endpoint like what I did in FetchData.js? I tried to replace localhost with the endpoint url, no luck; tried to type the endpoint url in a browser, could not see its content. I suppose I need to be able to see its content to be able to fetch data?
I will give you most simple difference
Fetch is a way to access HTTP resources like http://localhost:4000/my-project.
Your RDS endpoint (Most probably MYSQL) does not run an HTTP server.
So these endpoints (Links) are different, and they are not for the same purpose.
Edit:
You could connect to RDS using a MYSQL client from your server running on http://localhost:4000 which then return the data to fetch request.

"Cross Origin Request Blocked" No solutions seem to work

Background
I'm building a MERN full stack application as a personal project. I am running the frontend client on localhost:3000 and the server on localhost:5000.
Problem
All of my API routes work as expected except for a GET request, router.get('/get-friends', ...) which queries the mongoDB to return a list of collection documents. Calling that get request on Postman returns the expected output. I decided to write a simple GET request that returns a method and it works just fine in my browser
When making the request the get-friends request in my browser, I get the following log:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/api/users/get-friends/. (Reason: CORS request did not succeed)
What I've Already Tried
Enabling cors in my Express server
Enabling cors preflight
Adding a proxy to the server from the client's package.json
Switching from Axios to vanilla JS's fetch() method
Turning off cors in my browser
I suspect the issue occurs when I make the request to the database from Express. I am really not sure how to solve this issue.
Here is the route in question:
router.get('/get-friends', (req, res) =>{
var species_ = req.body.species;
var gender_ = req.body.gender;
var neutered_ = req.body.neutered;
// query db
Friend.find({species: species_},{gender:gender_},{neutered:neutered_}).then((friends_) =>{
if(!friends_){
return res.status(404).send('query error, nothing returned');
}
return res.send(friends_);
}).catch((e) =>{
res.status(400).send(4);
})
});
Here is the project repo and the relevant files are:
https://github.com/edgarvi/foster-friends/server.js (Express server)
https://github.com/EdgarVi/foster-friends/blob/master/routes/api/users.js (Routes for the express server)
https://github.com/EdgarVi/foster-friends/blob/master/client/src/components/layout/SearchFriends.js (React component which calls the server)
I would gladly appreciate any help!
I have highlighted possible problems.
Reason: CORS request did not succeed
The HTTP request which makes use of CORS failed because the HTTP
connection failed at either the network or protocol level. The error
is not directly related to CORS, but is a fundamental network error of
some kind.
> In many cases, it is caused by a browser plugin (e.g. an ad blocker or
privacy protector) blocking the request.
Other possible causes include:
Trying to access an https resource that has an invalid certificate
will cause this error.
Trying to access an http resource from a page with an https origin
will also cause this error.
As of Firefox 68, https pages are not permitted to access
http://localhost, although this may be changed by Bug 1488740.
> The server did not respond to the actual request (even if it responded
to the Preflight request). One scenario might be an HTTP service being
developed that panicked without returning any data.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSDidNotSucceed
Thank you all for the help and the suggestions. After struggling through this for multiple days, I finally encountered a solution.
In my react client, I made the API call:
axios.get('http://localhost:5000/api/users/get-friends',
{
params: {
species: this.state.species,
gender: this.state.gender,
neutured: neutered_
}}
);
and then I changed the Mongoose query to look like:
router.get('/get-friends', (req, res) =>{
var species_ = req.query.species;
var gender_ = req.query.gender;
var neutered_ = req.query.neutered;
// query db
Friend.find({species: species_},{gender:gender_},{neutered:neutered_}).then((_friends) => {
return res.send(_friends);
})
});
I'm not exactly sure why these changes made my code finally work but once again, thank you all for the help and suggestions!

calling axios in vue get Network Error

I working on one small project. Server side realized on Python as RESTFul server. Front-end I try do with Vue. I'm new in Vue. And when I try to fetch data fro service I get Error: Network Error. And I can't found mistake.
Irony is that I see fetched data in browser in network->Response tab. But not on HTML page. On the page I see Error: Network Error only.
I can fetch data with browser directly, by url.
I can fetch data with CURL
Also I can fetch data with this Vue code from third-part services! But not from local URL.
FLASK SERVER CODE
#app.route('/', methods=['GET'])
def get_data_list():
return 'Test'
VUE code
var app = new Vue({
el: '#app',
data: {
data_list: '...',
url_A: "#home",
url_B: '#page2',
url_C: '#settings'
},
created: function () {
this.loadData()
},
methods:
{
loadData: function () {
this.data_list = "Loading...."
var app = this
axios.get('http://127.0.0.1:5000/')
.then(function (response) {
app.data_list = response.data[0]
})
.catch(function (error) {
app.data_list = "An error occurred. "+error+" / Error ststus: "+error.response
})
}
}
})
I'm a little bit confused. What is wrong with my code?
You have mentioned that you are getting this error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at 127.0.0.1:5000. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
This means you have a CORS (Cross Origin Resource Sharing). Which means you are trying to send and/or receive request from two different domains/ports.
So, for example if you send a GET request from localhost:8080 to localhost:5000 you'll get the same error, because you are trying to share resources across different origins:
So, one way to fix this problem is to instruct your back-end server (127.0.0.1:5000) which I assume is running a flask app to allow you to send it a GET request from (127.0.0.1:8080).
So, configure your flask app with this CORS guide http://flask-cors.readthedocs.io/en/latest/

Resources