How do I create a website with a React Front end and a Flask backend?
I have created websites using flask and templates, and I have made pages using react, and now I would like to combine them.
I have tried a few things and the only things that worked required going into react config files and were very complicated. And even then it was complicated to use fetch and I had to run npm run build every time I changed the react file.
This seems to me like something that would be done all of the time yet I can't find any simple resources to do this.
Is there something that I fundamentally don't understand regarding websites and I am going at this the wrong way?
Focusing on a development workflow, as there are countless choices in how to deploy to a production environment.
Run your Flask app with /api as the root url prefix, either manually by prefixing all your route decorators or with the use of a Blueprint.
py/app.py
#app.route('/api')
def index():
return {'message':'hello'}
Add the Flask development server url to your package.json file
js/package.json
{
...,
"proxy": "http://localhost:5000"
}
Fetch your data using a component
js/Flask.js
import React, { Component } from 'react'
export class Flask extends Component {
constructor(props) {
super(props)
this.state = { data: {}, status: null }
}
fetchData() {
let status
fetch('/api')
.then((res) => {
return {
data: res.json(),
status: status
}
})
.then((data) => {
this.setState({ ...data })
}
.catch((err) => {
console.error(err)
})
}
componentDidMount() {
this.fetchData()
}
render() {
const { data, status } = this.state
return (
<div>
<h3>Status: { status }</h3>
<pre>
{ JSON.stringify(data) }
</pre>
</div>
)
}
}
export default Flask
Finally, include the component in your main App
js/App.js
import React from 'react';
import Flask from './Flask'
function App() {
return (
<div className="App">
<Flask />
</div>
);
}
export default App;
Start your Flask server with your preferred method, either flask run or by executing your script directly, then start your JS development server with either yarn or npm start. You should see the response from your api route displayed at http://localhost:8000
As long as you are running your Flask server with debug=True and use npm start (not npm run build), any changes made with either the backend or frontend will be automatically detected and your app reloaded.
Related
Working locally, I'm trying to pull some data from an api endpoint into a react front-end. Here's what I have:-
Data source/api endpoint (api platform, symfony)
http://127.0.0.1:8000/api/users?page=1
Front-end, React
http://127.0.0.1:3000/
/src/App.js
import React from 'react';
fetch('http://127.0.0.1:8000/api/users?page=1')
.then(response => console.log(response))
.then(json => console.log(json))
function App() {
return (
<div className="App">
</div>
);
}
export default App;
Firstly, I had to overcome a CORS issue with my data source. In symfony;-
.env
###> nelmio/cors-bundle ###
CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$'
###< nelmio/cors-bundle ###
As a side note; For my api endpoint (data source) - I can return the json response fine using both cURL and postman. However, if I try directly in a browser address bar, I just get my api landing page back i.e. swagger doc.
I'm wondering if this is an issue with headers not being set?
Back in my react app http://127.0.0.1:3000/ and at the console;-
my response is showing a 200 as you can see from above, but my json variable has a length of zero? So, no data.
Any ideas on how to pull the data (json) through to my react app using the above technique?
Here's what I was looking for in the end...
import React from 'react';
import { useEffect } from 'react'
function App() {
useEffect(() => {
fetch("http://127.0.0.1:8000/api/users?page=1")
.then((response) => response.json())
.then((response) => {
console.log(response);
})
}, []);
return (
<div className="App">
</div>
);
}
export default App;
I created a Google Cloud Platform account, and made a simple hello_world type Python "Cloud Function" that just spits out some simple text. I made this function "HTTP" accessible and only able to be called/authenticated by a "Service Account" that I made for the purpose of calling this very function. I generated a key for this "Service Account" and downloaded the json file for the key.
The problem is that I can't find any documentation on how to call this function with my service account in a next.js app. I tried this:
import React from 'react';
import { Button } from 'react-bootstrap';
import { GoogleAuth } from 'google-auth-library';
const projectId = 'gtwitone';
const keyFilename = '/Users/<myusername>/path/to/cloudfunction/credentials.json';
class Middle extends React.Component {
handleClick() {
console.log('this is:', this);
}
// This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); }
/* async listFunctions() {
const [functions] = await client.listFunctions();
console.info(functions);
} */
async runGoogleCloudFunctionTest() {
// Define your URL, here with Cloud Run but the security is exactly the same with Cloud Functions (same underlying infrastructure)
const url = "https://us-central1-<projectname>.cloudfunctions.net/<functionname>"
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({keyFilename: keyFilename})
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url);
const res = await client.request({url});
console.log(res.data);
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant='primary' onClick={this.runGoogleCloudFunctionTest}>
Click me
</Button>
</div>
);
}
}
export default Middle;
But I got this error in my terminal:
<myusername>#<mycomputername> <thisnextjsappdirectory> % yarn dev
yarn run v1.22.17
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
wait - compiling...
event - compiled client and server successfully in 267 ms (124 modules)
wait - compiling / (client and server)...
wait - compiling...
error - ./node_modules/google-auth-library/build/src/auth/googleauth.js:17:0
Module not found: Can't resolve 'child_process'
Import trace for requested module:
./node_modules/google-auth-library/build/src/index.js
./components/Middle.tsx
./pages/index.tsx
https://nextjs.org/docs/messages/module-not-found
Native Node.js APIs are not supported in the Edge Runtime. Found `child_process` imported.
Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json
^C
<myusername>#<mycomputername> <thisnextjsappdirectory> %
I know that this is problem with server side rendering in my Next.js app and people recommend using a client side package like this https://github.com/google/google-api-javascript-client. But google-api-javascript-client doesn't have any documentation on authenticating with a .json credentials file instead of an API KEY which I do not have.
In short how do I get my app to work and run the Google Cloud function with a .json credentials file for am authenticated service account?
I fixed it by simply moving the GoogleAuth api call to the pages/api route.
pages/api/google.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next"
import { GoogleAuth } from "google-auth-library"
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const url = process.env.FUNCTION_URL as string
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({ keyFilename: process.env.KEYSTORE_PATH })
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url)
const result = await client.request({ url })
console.log(result.data)
res.json({ data: result.data })
}
components/Middle.tsx
import React from "react"
import { Button } from "react-bootstrap"
class Middle extends React.Component {
handleClick() {
console.log("this is:", this)
}
// this talks with /pages/api/google
async imCallingAnAPI() {
const result = await fetch("/api/google")
console.log({ result })
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant="primary" onClick={this.imCallingAnAPI}>
Click me
</Button>
</div>
)
}
}
export default Middle
pages/index.tsx
import type { NextPage } from 'next'
import Header from '../components/Header';
import Footer from '../components/Footer';
import Middle from '../components/Middle';
const Home: NextPage = () => {
return (
<><main className='d-flex flex-column min-vh-100'>
<Header />
<br></br>
<br></br>
<Middle />
</main>
<footer>
<Footer />
</footer>
</>
)
}
export default Home
I think that next.js has trouble loading GoogleAuth in a component. I'm not 100% sure why, but I think it has to do with next.js not knowing exactly how to handle GoogleAuth with server-side rendering.
I am trying to use react-recaptcha-v3 (https://www.npmjs.com/package/react-recaptcha-v3) and I exactly wrote the example :
import React, { Component } from 'react';
import { ReCaptcha } from 'react-recaptcha-v3'
import { loadReCaptcha } from 'react-recaptcha-v3'
class ExampleComponent extends Component {
verifyCallback = (recaptchaToken) => {
// Here you will get the final recaptchaToken!!!
console.log(recaptchaToken, "<= your recaptcha token")
}
componentDidMount() {
loadReCaptcha('site key (I can't give it here)')
}
render() {
return (
<div>
<ReCaptcha
sitekey="site key (I can't give it here)"
action={console.log('action')}
verifyCallback={this.verifyCallback}
/>
<h2>Google ReCaptcha with React </h2>
<code>
1. Add <strong>your site key</strong> in the ReCaptcha component. <br/>
2. Check <strong>console</strong> to see the token.
</code>
</div>
);
};
};
export default ExampleComponent;
I wrote my domains names like this :
localhost
localhost:3000
And I got a site key and a secret key.
Here is what i get in console :
New answer :)
Firstly, I'm unsure if you said you added localhost & localhost:3000 to allowed domains. If you did you should remove them
We advise to use a separate key for development and production and to not allow localhost on your production site key.
Even if you are using this for a test environment I wouldn't recommend it. Instead use the test site key & secret key. Localhost is enabled for test.
Next, I noticed your comment about using reCaptcha v2. If you are trying to implement reCaptcha the way v3 intends this won't work.
reCaptcha v2
Adds a script to a div that detects a users input checking if they a human.
reCaptcha v3
Adds an invisible div that detects wether it thinks the user is a bot or not. You have to setup a backend for it to work. It creates a score from 0.0 to 1.0. 0.0 meaning it is most likely a bot, 1.0 meaing it is most likely a human. It uses a token and then on your backend gives you a response that looks like this.
{
"success": true|false, // whether this request was a valid reCAPTCHA token for your site
"score": number // the score for this request (0.0 - 1.0)
"action": string // the action name for this request (important to verify)
"challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"hostname": string, // the hostname of the site where the reCAPTCHA was solved
"error-codes": [...] // optional
}
https://developers.google.com/recaptcha/docs/faq
Next, I checked the documentation of the package.
You can't use loadReCaptcha in the same component, it must be in a Parent. Also action={console.log('action')} needs to be a string action="action" you configure this string in your google account.
https://developers.google.com/recaptcha/docs/v3#frontend_integration
Next, I won't recommend relying on a package as you make an uanessacry dependency.
I wrote an article here about it https://medium.com/#alexjamesdunlop/unnecessary-packages-b3623219d86.
import React, { Component } from 'react';
class ExampleComponent extends Component {
componentDidMount() {
const script = document.createElement("script")
script.src = "https://www.google.com/recaptcha/api.js?render=_reCAPTCHA_site_key"
script.addEventListener("load", () => {
window.grecaptcha.ready(function() {
window.grecaptcha.execute('_reCAPTCHA_site_key_', {action: 'homepage'}).then(function(token) {
// ...
});
});
})
document.body.appendChild(script)
}
render() {
return (
<div
className="g-recaptcha"
data-sitekey="_Your_Key_"
data-size="invisible"
>
</div>
)
}
}
export default ExampleComponent;
If you do want to continue using the package this is what it should look like.
import React, { Component } from 'react';
import { loadReCaptcha, ReCaptcha } from 'react-recaptcha-v3'
class ExampleComponent extends Component {
verifyCallback = (token) => {
// This is the token you send to your backend
console.log("token: ", token)
}
render() {
return (
<div>
<ReCaptcha
sitekey={your_site_key}
// This must be a string and an example google gives is 'homepage' or 'login'
action="action"
verifyCallback={this.verifyCallback}
/>
</div>
)
}
}
class ParentComponent extends Component {
componentDidMount() {
loadReCaptcha(your_site_key)
}
render() {
return <ExampleComponent />
}
}
export default ParentComponent;
Now if you did want to use v2 instead of v3 I show how to do that in the article
https://medium.com/#alexjamesdunlop/unnecessary-packages-b3623219d86
I recommend moving away from react Components and moving towards hooks, it's common practice to move away from it now, Components isn't supported.
https://reactjs.org/docs/hooks-effect.html
I created complete offline ReactJS web application and I want to run it from android application from Web View using React-Native.
I followed the following procedure to do so:
1. I created a compiled ReactJS web application got the build using the following command:
npm run build
Then I created react-native project and placed the build folder with following architecture
I updated App.js with the following content:
import React, {Component} from 'react';
import {Platform, StyleSheet, Text, View, WebView} from 'react-native';
import {roscon} from "./build/index.html";
type Props = {};
export default class App extends Component<Props> {
render() {
return (
<View style={{height: 300, width: 300,overflow:'hidden' }}>
<WebView
source={{uri: roscon}}
scalesPageToFit={true}
domStorageEnabled={true}
javaScriptEnabled={true}
startInLoadingState={true}
/>
</View>
);
}
}
After running this code I expected it to run my ReactJS Web application, instead I got white screen.
Can you please tell what can be the causing issues and how i can make my ReactJS Web App run on react-native?
Note: I was able to run generated build folder using npm command
serve -s build
But I still can't figure out how to port it to react-native project as WebView
After research and testing, I found a solution.
The main issue i found was the compiled build folder is rendered as static html. And it needed a server to serve pages.
So, I followed this link for getting build project to get it up and running
Then, integrating it with nodejs Android Project Samples to get my build folder running in android as a Webview.
Note: I also tried react-snapshot and react-snap but they didn't gave satisfactory results.
Try to require the html file correctly and pass it in to source prop in this way:
<WebView
source={require('./build/index.html')}
/>
Install
npm install react-native-react-bridge
These are used to render React app in WebView
npm install react-dom react-native-webview
Requirements
react 16.8+
react-native 0.60+
Usage
Fix metro.config.js to use babelTransformer from this library.
module.exports = {
transformer: {
babelTransformerPath:
require.resolve('react-native-react- >.
.bridge/lib/plugin'),
...
},
};
Make entry file for React app. web.js
import React, { useState } from "react";
import {
webViewRender,
emit,
useSubscribe,
} from "react-native-react-bridge/lib/web";
const Root = () => {
const [data, setData] = useState("");
// useSubscribe hook receives message from React Native
useSubscribe((message) => {
if (message.type === "success") {
setData(message.data);
}
});
return (
<div>
<div>{data}</div>
<button
onClick={() => {
// emit sends message to React Native
// type: event name
// data: some data which will be serialized by JSON.stringify
emit({ type: "hello", data: 123 });
}}
/>
</div>
);
};
// This statement is detected by babelTransformer as an entry point
// All dependencies are resolved, compressed and stringified into one file
export default webViewRender(<Root />);
Use the entry file in your React Native app with WebView.
import React from "react";
import WebView from "react-native-webview";
import { useBridge } from "react-native-react-bridge";
import webApp from "./WebApp";
const App = () => {
// useBridge hook create props for WebView and handle communication
// 1st argument is the source code of React app
// 2nd argument is callback to receive message from React
const { ref, source, onMessage, emit } = useBridge(webApp, (message) => {
// emit sends message to React
// type: event name
// data: some data which will be serialized by JSON.stringify
if (message.type === "hello" && message.data === 123) {
emit({ type: "success", data: "succeeded!" });
}
});
return (
<WebView
// ref, source and onMessage must be passed to react-native-webview
ref={ref}
source={source}
onMessage={onMessage}
/>
);
};
I'm trying to connect my Django backend to a React Frontend using axios to access the api endpoint. I have tested the api using curl to see if I receive a json of the test data, it is fine. I have opened up the endpoint so that it does not need authentication. But I keep on getting this error in my javascript console:
edit: for to say that I am running the api and frontend on my computer
Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
Test.js- Test component to test out feeding backend to frontend. I would like to console log the data but only catch the error.
import React, {Component} from 'react'
import axios from 'axios';
class Test extends Component{
constructor(){
super();
this.state = {
messages:[],
}
}
componentDidMount(){
axios.get('http://127.0.0.1:8000/api/message/?format=json')
.then(res=> {
console.log(res);
})
.catch(error =>{
console.log(error);
});
}
render(){
return(
<div>
<h1>
Message:
</h1>
</div>
)
}
}
export default Test;
I needed to setup CORS on my django api. The issue was not with my front end but by backend not being setup properly. Whenever you have api request from a different server you have to setup CORS on the backend.