HTTPS error on deployed React project - reactjs

I was trying to host my React project on GH Pages. The deploy worked fine but when I try to search for gifs I get the following error
http_browser.js:47 Mixed Content: The page at
'https://pimmesz.github.io/react-giphy/' was loaded over HTTPS, but
requested an insecure XMLHttpRequest endpoint
'http://api.giphy.com/v1/gifs/search?
q=h&limit=10&rating=g&api_key=MYAPIKEY'. This request has been blocked; the
content must be served over HTTPS.
It seems like the Giphy API is making a http request instead of https. Is there a way to change the default url which the API uses?
import React, { Component } from 'react';
import giphy from 'giphy-api';
import Search from './search.jsx';
import Gif from './gif.jsx';
import GifList from './gif_list.jsx';
class App extends Component {
constructor(props) {
super(props);
this.state = {
gifs: [],
gif: "xBoysJgwhLEZtAjbY1"
}
}
search = (query) => {
giphy('APIKEY').search({
q: query,
limit: 10,
rating: 'g'
}, (err, res) => {
this.setState({gifs: res.data})
});
}
select = (id) => {
this.setState({gif: id})
}
render() {
const gifs = this.state.gifs;
return (
<div>
<div className="left-scene">
<Search search={this.search}/>
<Gif id={this.state.gif} select={this.select} />
</div>
<div className="right-scene">
<GifList gifs={gifs} select={this.select} />
</div>
</div>
);
}
}
export default App;

Changed the giphy API execution to
const url = `https://api.giphy.com/v1/gifs/search?q=${query}&limit=10&rating=g&api_key=MY_API_KEY`
fetch(url)
.then(results => { return results.json();
}).then(data => {
this.setState({gifs: data.data});
});
EDIT
Found another way!
Setting https to true can be done as an option in the giphy api call
giphy({ apiKey: "MY_API_KEY", https: true })

Related

Passing header parameters while loading Video in VideoJs

I am trying to load a video into VideoJS player in a react project. The Video is returned from a web service taking specific token that authenticate the user.
Let's say the video is returned from the below API call:
localhost:8080/video/1/
In order to play this video, the user should be authenticated. In other words, the API takes the below header to return a successful result:
auth: token
My VideoJs player is built in a React component as below:
import React from 'react'
import videojs from 'video.js'
export default class VideoComponent extends React.Component {
componentDidMount () {
this.videoJsOptions = {
sources: [{
src: 'http://localhost:8080/video/1/',
type: 'video/mp4',
}],
}
let player = videojs(this.videoNode, this.videoJsOptions, function onPlayerReady() {
console.log('onPlayerReady', this)
})
this.player = player
}
render () {
return (
<div data-vjs-player>
<video ref={node => this.videoNode = node} className="video-js"></video>
</div>
)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
How is it possible to let my video component take the token of the calling URL and pass it the request header?
I would put this component as a child of another component whose sole responsibility is to make the API call and render the VideoComponent if the user is authorized. Something along these lines.
You'll probably want some type of redirect or error message feedback to the user if they are not authorized. I did not incorporate that in my code snippet.
export default class VideoAuth extends React.Component {
state = {
isAuthorized: false
}
async componentDidMount() {
const authRequest = await someAuthRequest()
if (authRequest.ok) {// or however the data structure looks like
this.setState({ isAuthenticated: true })
}
}
render() {
return this.state.isAuthenticated ? <VideoComponent /> : <div> Authorizing... </div>
}
}

Fetch data from GET request

When I call my API via my web browser I get the following result:
{"statusCode": 200, "body": "\"Cheers from AWS Lambda!\""}
However, I am now struggeling to show body via axios. Do you see what I am doing wrong?
import axios from "axios";
import React, { Component } from "react";
class App extends Component {
state = {
messages: []
};
componentDidMount() {
axios
.get(
"https://12345.execute-api.eu-central-1.amazonaws.com/prod/get-data"
)
.then(response => {
const messages = response.data;
this.setState({ messages });
});
}
render() {
return (
<ul>
{this.messages}
Test
{this.state.messages.map(message => (
<li>{message}</li>
))}
</ul>
);
}
}
export default App;
A few points:
1) Change this.messages in ul of render method to this.state.messages, as this.messages is undefined.
2) A good practice while using JSX is to keep js and html code as distinguishable as possible, so the map on a list should be done outside the return statement.
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
3) For more info about CORS error and how to rectify it while using AWS lambda, refer to this article which includes a code snippet: AWS: CORS

SSO react-google-login with google on react app using a react component

I got question about implementing google login. I was able to implement Google Login button on my react app using an open source library called [react-google-login][1]. I was able to set up the backend server using python flask, and host the api on Heroku: http://arrangement-server.herokuapp.com/login. The client side should just be redirecting to google and then getting a token when it redirects back.
But I have trouble to getting any token from Google login information on the frontend through react component.
I think there's an issue with my header for access token and request from [app.py][2]
google = oauth.remote_app('google',
base_url='https://www.google.com/accounts/',
authorize_url='https://accounts.google.com/o/oauth2/auth',
request_token_url=None,
request_token_params={'scope': 'https://www.googleapis.com/auth/userinfo.email',
'response_type': 'code'},
access_token_url='https://accounts.google.com/o/oauth2/token',
access_token_method='POST',
access_token_params={'grant_type': 'authorization_code'},
consumer_key=GOOGLE_CLIENT_ID,
consumer_secret=GOOGLE_CLIENT_SECRET)
#app.route("/")
def home_page():
access_token = session.get('access_token')
if access_token is None:
return redirect(url_for('login'))
access_token = access_token[0]
from urllib2 import Request, urlopen, URLError
headers = {'Authorization': 'OAuth '+access_token}
req = Request('https://www.googleapis.com/oauth2/v1/userinfo',
None, headers)
try:
res = urlopen(req)
except URLError, e:
if e.code == 401:
# Unauthorized - bad token
session.pop('access_token', None)
return redirect(url_for('login'))
return res.read()
return res.read()
my react component at App.js
import React, { Component } from 'react'
import './App.css'
import router from 'config/router'
import { Provider } from 'react-redux'
import store from 'store/index'
import { GoogleLogin } from 'react-google-login'
import config from './config.json'
class App extends Component {
constructor() {
super();
this.state = { isAuthenticated: false, user: null, token:
''};
}
logout = () => {
this.setState({isAuthenticated: false, token: '', user: null})
};
onFailure = (error) => {
alert(error);
};
googleResponse = (response) => {
console.log(response);
const tokenBlob = new Blob([JSON.stringify({access_token: response.accessToken}, null, 2)], {type : 'application/json'});
const options = {
method: 'POST',
body: tokenBlob,
mode: 'cors',
cache: 'default'
};
fetch('http://arrangement-server.herokuapp.com/login', options).then(r => {
const token = r.headers.get('x-auth-token');
r.json().then(user => {
if (token) {
this.setState({isAuthenticated: true, user, token})
}
});
})
};
render() {
let content = !!this.state.isAuthenticated ?
(
<div>
<p>Authenticated</p>
<div>
{this.state.user.email}
</div>
<div>
<button onClick={this.logout} className="button">
Log out
</button>
</div>
</div>
) :
(
<div>
<GoogleLogin
clientId={config.GOOGLE_CLIENT_ID}
buttonText="Login"
onSuccess={this.googleResponse}
onFailure={this.onFailure}
/>
</div>
);
return (
<div className="App">
{content}
</div>
);
}
}
export default App
Code above can be found at my project
/login route verb should be POST
I have looked your code. I am able to run that with your google client Id.
So, at the frontend token and profile details are getting with "react-google-login".
The problem is at the /login api. This api should be "POST".
You can check my attached screenshot.
I saw you have created config.json for id and secrets but forgot to drop the commit which had the client Id. Shouldn't commit the configId's in code :P
So, The Frontend using the react library react-google-login gets the access token from google server. So the backend side doesn't need to get the access token. The front end side needs to give the access token to the backend side via post request.

Failed call to Deezer API with React and axios

I want to connect to Deezer API and read data, the API is available here, if you take first links they have there and open in a new tab you will see the data in json, however Axios can't return it
import React from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import "./styles.css";
class App extends React.Component {
componentDidMount() {
axios.get("https://api.deezer.com/album/302127")
.then(response => {
console.log(response);
})
.catch(err => {
console.log(err);
});
}
render() {
return (
<div className="App">
<h2>Deezer</h2>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Deezer api don't allow cross-origin request. So an api call from browser is not possible.
However you can use a workaround and use https://cors-anywhere.herokuapp.com
You need to change your code like following:
axios.get("https://cors-anywhere.herokuapp.com/https://api.deezer.com/album/302127")
.then(response => {
this.setState({ response })
})
.catch(err => {
console.log('error', err);
});
Here is a working example: https://stackblitz.com/edit/react-v6bufu
However, I will recommend to code your own backend where you will call
Deezer's APIs. You won't be getting cross-origin error there.

Retrieve messages from app like trello in real time - Slack

I'm using slack API to retrieve messages from bot app (like trello in slack.com). I used this API https://slack.com/api/im.history. But my goal, is to get messages from that bot app in real time to my application without reloading page. I already read the RTM API docs, and also The events API. I didn't figure out how to do so. What should I do ?
Here is server/main.js :
import { Meteor } from 'meteor/meteor';
import { HTTP } from 'meteor/http';
import '../imports/api/messages.js';
Meteor.startup(() => {
Meteor.methods({
checkSlack() {
this.unblock();
try {
var result = HTTP.call('GET','https://slack.com/api/im.history', {
params: {
token: 'xxxx-xxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx',
channel: 'xxxxxxxxxx'
}
});
return result.data.messages;
} catch (error) {
// Got a network error, timeout, or HTTP error in the 400 or 500 range.
return error.message;
}
}
});
});
imports/api/messages.js:
import { Mongo } from 'meteor/mongo';
export const Messages = new Mongo.Collection('messages');
if (Meteor.isServer) {
// This code only runs on the server
Meteor.publish('messages', function messagesPublication() {
return Messages.find();
});
}
imports/ui/Message.jsx:
import React, { Component, PropTypes } from 'react';
export default class Message extends Component {
render() {
return (
<li>{this.props.message.text}</li>
);
}
}
Message.propTypes = {
message: PropTypes.object.isRequired,
};
imports/ui/App.jsx:
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import { Messages } from '../api/messages.js';
import Message from './Message.jsx';
const _ = require('lodash');
// App component - represents the whole app
class App extends Component {
constructor(props){
super(props);
this.state = {
messages: [],
};
this.renderMessages = this.renderMessages.bind(this);
this.getMessages = this.getMessages.bind(this);
this.saveMessages = this.saveMessages.bind(this);
}
componentDidMount() {
this.getMessages();
}
getMessages() {
const handle = this;
Meteor.call('checkSlack',function(err, response) {
if(err){
console.log('error');
}
else {
handle.setState({
messages: response,
});
}
});
};
renderMessages() {
const messages = Messages.find({}).fetch();
return messages.map((message, index) => (
<Message key={index} message={message} />
));
}
saveMessages(){
const messages = this.state.messages;
const msgs = Messages.find({}).fetch();
var addedMsgs = _.differenceBy(messages,msgs, 'ts');
_.map(addedMsgs, (message) =>
Messages.insert(message)
);
}
render() {
return (
<div className="container">
<header>
<h1>Messages List</h1>
</header>
<button onClick={this.saveMessages}>Save</button>
{this.renderMessages()}
</div>
);
}
}
App.propTypes = {
messages: PropTypes.array.isRequired,
};
export default createContainer(() => {
Meteor.subscribe('messages');
return {
messages: Messages.find({}).fetch(),
};
}, App);
client/main.jsx:
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import App from '../imports/ui/App.jsx';
Meteor.startup(() => {
render(<App />, document.getElementById('render-target'));
});
client/main.html:
<head>
<title>App</title>
</head>
<body>
<div id="render-target"></div>
</body>
If you can get the Slack events coming through from the API, to a Meteor server, simply insert them into a Mongo collection, and then set up your Meteor client to subscribe to the database, and you will have a real time feed to your UI
UPDATE
Thanks for possting your code, now I can see what's going on.
1) In your server code you are doing this:
Meteor.startup(() => {
Meteor.methods({
It probably works OK, but these are independent things. Meteor methods often lives in another file, and is just used to declare your methods.
2) You only save the messages to the collection from the UI. They need to be inserted when you get them in the server method - then your publication and subscription will work
3) Remove the call to checkSlack from componentDidMount, and put it in the server startup.
4) Your http request to slack will only retrieve the history, you need to get more sophisticated here. Read https://api.slack.com/rtm for how you can open a socket and get a real time feed

Resources