Can't access CakePHP API endpoint via ReactJS. Only through the browser - reactjs

I am trying to build a REST API for my server via CakePHP. I thought I had it working as I can receive the JSON responses via the web browser however when trying to access the same route via ReactJS, the Controllers Action is not actually firing.
Reading the CakePHP docs I really should only have to implement these lines of code to get the API working (According to the docs) and I did:
/config/routes.php
Router::scope('/', function($routes) {
$routes->setExtensions(['json']);
$routes->resources('Users');
});
Here is the API Endpoint I want to hit:
`public function signUp() {
$file = fopen("error_log.txt", "w");
$txt = "firing endpoint";
$fwrite($file, $txt);
$fclose($file);
$response = $this->response;
$responseText = [
"status" => "200",
"message" => "User added successfully"
];
$response = $response->withType("application/json")
->withStringBody(json_encode($responseText));
return $response;
}`
Here I am successfully hitting that endpoint via the browser. My log message also appears in the error_log.txt file
Here is where I'm making a request via ReactJS:
handleRequest = () => {
console.log('making request');
axios({
method: 'get',
url: 'https://157.230.176.243/users/register.json',
data: {
email: this.state.email,
password: this.state.password
}
})
.then(function(response) {
console.log('got response');
console.log(response);
})
.catch(function(error) {
console.log('got error');
console.log(error);
})
.then(function(data) {
console.log('always executed');
console.log(data);
});
}
When I make this request via ReactJS I get a XHR failed loading: OPTIONS "https://157.230.176.243/users/register.json"
Also when making this request via ReactJS my log message does not get written to error_log.txt

Ok I finally figured out what was wrong. I have my React Development server running on
157.230.176.243:3001
and my CakePHP API served on that same server,
157.230.176.243
React didn't like it that I was passing the full URL of the API to the fetch()
call. I switched my React code to
url: "/users/register.json"
and it works fine.

Related

Expressjs Server cannot handle Requests from the Outside

I have a ExpressJs Server with React Components. And the Server should handle Requests from Outside and one request should play a Song from the Spotify API when not currently playing.
app.post("/play", (req, res) => {
try {
// requesting to play uses query params
id = req.query.id;
currPlayingID = 0;
// get the currently playing song from the SPotify API
axios({
url: "https://api.spotify.com/v1/me/player/currently-playing",
method: "get",
headers: {
authorization: `Bearer ${access_token}`,
},
})
// set the currently Playing ID or to zero if nothing is playing
.then((response) => {
if (response.data !== null) {
currPlayingID = response.data.id;
} else {
currPlayingID = 0;
}
});
// only play the song if its not currently playing
if (id !== currPlayingID) {
// making a axios request to the Spotify API to play the Song with the ID
axios({
url: "https://api.spotify.com/v1/me/player/play/",
method: "put",
headers: {
authorization: `Bearer ${access_token}`,
},
data: {
uris: [`spotify:track:${id}`],
},
});
res.status(204);
}
} catch (error) {
res
.status(404)
.json({ message: "Couldn't get Info from Spotify API", error: error });
}
});
The Problem:
The Code works when I start the server on the device itself (so a local server on my Desktop PC), but when I start the Server on my RaspberryPI i cannot handle Requests to this endpoint /play. Yeah I updated all the IP Adresses, everywhere.
But the moer ointeresting part is using the React Client I get this error:
Failed to load resource: net::ERR_CONNECTION_REFUSED
Requesting with POSTMAN I get the following:
Mixed Content Error: The request has been blocked because it requested an insecure HTTP resource
And from a request using a python script I get on the server side:
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "AxiosError: Request failed with status code 400".] {
code: 'ERR_UNHANDLED_REJECTION'
}
I have no clue how to fix each error and if it is one fix. Basically I found out it is a Problem with rejeccting requests from outside localhost, because with cURL on my ssh terminal it works.
I'm learning express, so I m not an expert, but I'm looking at your errors. I will suggest you try asyncHandler module. It handles asynchronous requests and exceptions.
I faced a similar issue because while I'm sending the API request via
Axios, my token is null/empty/wrong, so make sure your token is correct
this is my request format
axios({
method:"POST",
url:"https://graph.facebook.com/v13.0/"+phon_no_id+"/message?access_token="+token,
data:{
messaging_product:"whatsapp",
to:from,
text:{
body:"Hi.. I'm Prasath"
}
},
headers:{
"Content-Type":"application/json"
}
});

How to fetch data from a REST API by using an API-Token

I'm trying to fetch data from the Jira Rest API in my React application by using the Axios library for http requests. An API token is necessary, in order to access data via the Jira API. I generated an API token in my Jira account settings, but I can't figure out, how to include it in my http request to gain access.
This is the endpoint provided by the Jira documentation for getting an issue from the Jira board:
curl -u admin:admin http://localhost:8080/jira/rest/api/2/issue/TEST-10 | python -mjson.tool
This is the React state hook for setting the data to the fetched data:
const [jiraTicket, setJiraTicket] = useState([]);
This is the fetch function for the API request (${} will be filled with user input):
function getJiraTicket() {
axios.get(`${username}:${apiToken}#Content-Type:application/json/https:/${jiraSiteName}.atlassian.net/rest/api/2/issue/${projectKey}-${ticketId}`)
.then((res) => {
const data = res.data;
setJiraTicket(data);
})
}
The button inside the react component return should invoke the fetch function:
return(
<Container>
<Button onClick{getJiraTicket()}>Fetch Jira Ticket</Button>
</Container>
);
This is the error I'm currently getting, because the authorization is not working the way I did it
(I replaced the provided username, API token etc. for this example):
GET http://localhost:3000/username:apitoken#https:/sitename.atlassian.net/rest/api/2/issue/projectkey-ticketid 404 (not found)
Edit:
My current approach:
function getJiraTicket() {
axios.get(`${userName}:${apiToken}#https://${siteName}.atlassian.net/rest/api/2/issue/${projectId}-${ticketId}`,{
auth: {
username: userName,
password: apiToken,
},
withCredentials: true
})
.then((res) => {
const data = res.data;
console.log(data);
setJiraTicket(data);
})
.catch(err => {
// This error means: The request was made and the server responded with a status code
if(err.res) {
console.log(err.res.data);
console.log(err.res.status);
console.log(err.res.headers);
console.log("request was made and server responded with status");
// The request was made but no response was received
} else if (err.request) {
console.log(err.request);
console.log("request was made, but no response was received");
// Something happened in setting up the request that triggered an error
} else {
console.log("Error", err.message);
console.log("request is note set up correctly");
}
console.log(err.config);
})
Current error, which I defined accordingly to the axios doc: "request was made, but no response was received"
Endpoint that works well in Postman (Basic auth is provided in Postman):
https://sitename.atlassian.net/rest/api/2/issue/projectid-ticketid
Update: CORS access isn't allowed, when an application tries to access the Jira API endpoints directly. This restriction takes place in order to prevent random authenticated requests to the specific Jira site, because the access is based on session based authentication. However the API endpoints can be accessed, if OAuth 2.0 is used instead of Basic auth, because the application will redirect the user to the Jira auth itself via this link:
https://auth.atlassian.com/authorize? audience=api.atlassian.com&
client_id=YOUR_CLIENT_ID&
scope=REQUESTED_SCOPE_ONE%20REQUESTED_SCOPE_TWO&
redirect_uri=https://YOUR_APP_CALLBACK_URL&
state=YOUR_USER_BOUND_VALUE& response_type=code& prompt=consent
Source: https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#known-issues
Axios uses a headers config for get/post so you should not include them in your URL. Here is a general example of how you should construct the URL and apply headers:
let axiosUrl = `https://${jiraSiteName}.atlassian.net/rest/api/2/issue/${projectKey}-${ticketId}`
axios({
baseURL: axiosUrl,
method: 'get',
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin", "*"
},
//timeout: 2000,
auth: {
username: userName,
password: apiToken,
}
})
.then((res) => {
setJiraTicket(res.data);
})
.catch(function (error) {
console.log(error);
});

Read cookie in AngularJs, REST API

So, I created my client application using angular to interact with my WCF REST API. I basically use cookies to store the login session and retrieve the information by sessions. This works perfectly from Postman and also with a console client application (there I created cookie container).
Now I have a problem to read the cookies from AngularJs. My HTTP response header shows the cookies but the angular response header is undefined.
AngularService.js:
this.login = function (credential) {
var request = $http({
method: "POST",
url: "someUrlLogin",
data: angular.toJson(credental),
config: { withCredentials: true },
});
return request;
}
AngularContoller.js :
var promisePost = AngularService.login(credential);
promisePost.then(function (response) {
$scope.loginResult = angular.fromJson(response);
$timeout(function () {
console.log(response.headers("Set-Cookie"); //null
console.log($cookies["ASP.NET_SessionId"]); //undefined
console.log($cookies.getAll); //undefined
},
function error (err) {
$scope.loginResult = err;
});
WCF REST session:
_context.Session["USERLOGGEDIN"] = "SomeValue"
I have set the HTTPOnly flag to false
I have also tried "console.log(response.headers("setcookie") which also doesn't work
"Access-Control-Allow-Credentials = true"
"Access-Control-Expose-Headers" value="content-type, Set-Cookie"
What else am I missing? Is it even possible to read the cookies from the http response headers?

How to send an HTTP GET request using Firebase and Angular?

My app uses IBM Watson Speech-to-Text, which requires an access token. From the command line I can get the access token with curl:
curl -X GET --user my-user-account:password \
--output token \
"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api"
When I make an HTTP request using Angular's $http service I get a CORS error:
var data = {
user: 'my-user-account:password',
output: 'token'
};
$http({
method: 'GET',
url: 'https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api',
data: data,
}).then(function successCallback(response) {
console.log("HTTP GET successful");
}, function errorCallback(response) {
console.log("HTTP GET failed");
});
The error message says:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://127.0.0.1:8080' is therefore not allowed
access. The response had HTTP status code 401.
As I understand, it's not possible to do CORS from Angular; CORS has to be done from the server. I know how to do CORS with Node but I'm using Firebase as the server.
Firebase has documentation about making HTTP requests with CORS. The documentation says to write this:
$scope.getIBMToken = functions.https.onRequest((req, res) => {
cors(req, res, () => {
});
});
First, that doesn't work. The error message is functions is not defined. Apparently functions isn't in the Firebase library? I call Firebase from index.html:
<script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
My controller injects dependencies for $firebaseArray, $firebaseAuth, and $firebaseStorage. Do I need to inject a dependency for $firebaseHttp or something like that?
Second, how do I specify the method ('GET'), the URL, and the data (my account and password)?
if you want to send credentials with angular, just set withCredentials=true. I am also using CORS with Angular v4, for your HTTP header error, you are right. Header Access-Control-Allow-Origin must be added on server side, check if you have settings in your api to allow certain domains, urls, pages, because google api's has this function, so check where you get token there should be some settings.
Here is example, how I am calling API with CORS, using typescript:
broadcastPresense(clientId: string) {
const headers = new Headers({'Content-Type':'application/json','withCredentials':'true'});
return this.http.post('http://localhost/api.php',
{
'jsonrpc': '2.0',
'method': 'somemethod',
'params': {'client_id': clientId},
'id': CommonClass.generateRandomString(16)
},{headers: headers, withCredentials:true}).map(
(res: Response) => {
console.log(res);
const data = res.json();
console.log(data);
if (data.error == null) {
return data.result;
} else if (data.error != null) {
throw data.error;
}
throw data.error;
}
).catch(
(error) => {
this.router.navigate(['/error',3],{queryParams: {desc:'Server error'}});
return Observable.throw(error);
}
);
}
Hope it helps :)
The answer is to use Cloud Functions for Firebase, which enable running Node functions from the server. Then you use the Node module request to send the HTTP request from Node.

How to call a function upon http get or post?

I'm sure this is a stupid question but I am very new to the backend so please forgive me.
I am building an angularjs app with express/node also and am trying to integrate PayPal (as a Node.js SDK), what I want is to call the pay method on the SDK from an angular controller and I am doing as follows:
On button click:
// controller
$scope.pay = function(amount) {
PaymentFactory.doPayment(amount);
}
Payment Factory:
// PaymentFactory
return {
doPayment: function(amount) {
$http.get("../../../server/payments/paypal.js")
.then(function(response) {
console.log( response );
})
}
}
Then the server-side file is as below:
require('paypal-adaptive');
var app = require('../../server.js');
var PayPal = require('paypal-adaptive');
var paypalSdk = new PayPal({
userId: 'userid',
password: 'password',
signature: 'signature',
sandbox: true //defaults to false
});
var payload = {
requestEnvelope: {
errorLanguage: 'en_US'
},
actionType: 'PAY_PRIMARY',
currencyCode: 'GBP',
feesPayer: 'EACHRECEIVER',
memo: 'Chained payment example',
cancelUrl: 'returnUrl,
returnUrl: 'cancelUrl',
receiverList: {
receiver: [
{
email: 'email1',
amount: '3.40',
primary:'true'
},
{
email: 'email2',
amount: '1.20',
primary:'false'
}
]
}
};
paypalSdk.pay(payload, function (err, response) {
if (err) {
console.log(err);
} else {
// Response will have the original Paypal API response
// But also a paymentApprovalUrl, so you can redirect the sender to checkout easily
console.log('Redirect to %s', response.paymentApprovalUrl);
return response;
}
});
Of course the get request just returns a string of the server-side file contents, I understand why the above doesn't work but not sure how one would make it work. My aim is to call the PayPal SDK from the angular factory and get back the response so that I can redirect a user to a URL. A direct solution would be helpful but even more so I need pointers to the principles that I am not understanding here as far as how one should call functions upon user actions to get this data from the server side. I have tried searching but I don't really the language to use in my search.
All you need to do is use curl (node-curl npm module). Using curl will help you post data to your paypal url and get back the response. Now you need to handle this response from paypal and accordingly generate your own response to be received by the angular http method.

Resources