I am trying to use ReactJS to build a simple website that pulls data from my Django REST Framework API. The issue I am running into, is that my data is not being output by React. I am certain that my Django backend is running flawlessly. I get no errors when running it, and can view my API data via "http://127.0.0.1:8000/api/".
Here is my frontend ReactJS code:
import React, { Component } from 'react';
class App extends Component {
state = {
usernames : []
};
async componentDidMount() {
try {
const res = await fetch('http://127.0.0.1:8000/api/');
const usernames = await res.json();
this.setState({
usernames
});
} catch (e) {
console.log(e);
}
}
render() {
return(
<div>
{this.state.usernames.map(item => (
<div key={item.id}>
<h1>{item.username}</h1>
</div>
))}
</div>
);
}
}
export default App
I have tried updated my CORS_ORIGIN_WHITELIST via settings.py and includes all variations of localhost.
When scripting with Python, I am able to make a request and retrieve my API data. This is the output:
[{'username': 'testname', 'created_at': '2019-12-06T00:03:50.833429Z'}, {'username': 'testname2', 'created_at': '2019-12-06T00:04:01.906974Z'}, {'username': 'testname3', 'created_at': '2019-12-06T00:04:05.330933Z'}, {'username': 'testname4', 'created_at': '2019-12-06T00:04:08.144381Z'}]
And though no ID is present in the output (Which I'm not sure why) I can still access the correct data by making a request like this: "http://127.0.0.1:8000/api/3/"
Any help is appreciated.
Set Access-Control-Allow-Origin: to * just for the purposes of local development. For security reasons you don't want to do that in production, but doing it on your local machine while you're dev'ing is fine. See here if you are unsure of how to: techiediaries.com/django-cors
To solve this issue, I had to install django-cors-headers. This can be done via pip install django-cors-headers
After that, I had to add the following to my settings.py file:
INSTALLED_APPS = [
##...
'corsheaders'
]
MIDDLEWARE_CLASSES = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.BrokenLinkEmailsMiddleware',
'django.middleware.common.CommonMiddleware',
#...
]
CORS_ORIGIN_ALLOW_ALL = True
Related
My POST requests to flask backend only work with JWT_COOKIE_CSRF_PROTECT = False, but GET requests work
config:
CSRF_ENABLED = True
CORS_SUPPORTS_CREDENTIALS = True
JWT_TOKEN_LOCATION = ['cookies']
I access flask through axios from the Vue app
const path1 = `/limit_engine/balance`;
axios
.post(path1, { withCredentials: true })
.then((response) => {
console.log(response.data["balance"]);
})
.catch((error) => {
console.error(error);
});
https://flask-jwt-extended.readthedocs.io/en/stable/options/#jwt-cookie-csrf-protect
suggests JWT_COOKIE_CSRF_PROTECT should be always True in production, so I cannot keep it False then
Try to debug the request by examining headers. If you are sending requests from the browser, you can use any of Dev Tools (Chrome for example). Take a look at the Network tab, look for your POST request, find out which cookies are sent.
If you can't find CSRF token in the request then you should pass it from the backend to the frontend and keep it in cookies storage.
After whole morning having trouble with this I realized CSRF token is only read from request headers as seen here: https://flask-jwt-extended.readthedocs.io/en/stable/_modules/flask_jwt_extended/view_decorators/ not from cookies, so in Vue you need to manually append this header to your requests.
Relevant source code to add to your flask app and to your Vue app:
In flask app:
app.config['JWT_ACCESS_CSRF_HEADER_NAME'] = "X-CSRF-TOKEN"
app.config['JWT_REFRESH_CSRF_HEADER_NAME'] = "X-CSRF-REFRESH-TOKEN"
app.config['JWT_CSRF_IN_COOKIES'] = False
In your flask app login function:
from flask_jwt_extended import (
jwt_required, create_access_token,
jwt_refresh_token_required, create_refresh_token,
get_jwt_identity, set_access_cookies,
set_refresh_cookies, get_raw_jwt, get_csrf_token
)
new_token = create_access_token(identity=current_user.id, fresh=False)
new_refresh_token=create_refresh_token(identity=current_user.id)
response = jsonify({
'data': {
'message':'Ok',
'type': 'user',
'id': current_user.id,
'meta': {
'accessToken': new_token,
'access_csrf_token': get_csrf_token(new_token),
'refreshToken': new_refresh_token,
'refresh_csrf_token': get_csrf_token(new_refresh_token)
}
}
})
set_refresh_cookies(response, new_refresh_token)
set_access_cookies(response, new_token)
return (response)
In your Vue app in your login fuction "edit according if you use or not refresh token logic":
axios.defaults.headers.common['X-CSRF-TOKEN']=response.data.data.meta.access_csrf_token
axios.defaults.headers.common['X-CSRF-REFRESH-TOKEN']=response.data.data.meta.refresh_csrf_token
And lastly do the same in yout Vue TokenRefreshPlugin or the method you use
I guess there are more approaches like getting the CSRF headers from the cookies, but this one seems to work for me for now at least. The important point is adding this headers manually in Vue requests, because using axios.defaults.withCredentials = true is not enough.
Also check header includes csrf token in the requests as akdev suggests.
you can add csrf exception for request.
or follow:-
https://flask-jwt-extended.readthedocs.io/en/3.0.0_release/tokens_in_cookies/
There are some data which would be sent frequently from a django server to the angularjs, this is a data which would be modified frequently and the modification would be updated at the front end when the changes are made at the backend
At the point where the data is made available I have inserted
views.py
send_event('test', 'message', {'text': dataModifiedFrequently})
asgi.py
application = ProtocolTypeRouter({
'http': URLRouter([
url(r'^event_url/', AuthMiddlewareStack(
URLRouter(django_eventstream.routing.urlpatterns)
), { 'channels': ['test'] }),
url(r'', get_asgi_application()),
]),
})
angular.js
$scope.EventSourceScope = function(){
if (typeof(EventSource) !== "undefined") {
var source = new EventSource('event_url');
source.onmessage = function (event) {
$scope.openListingsReport = event.data;
$scope.$apply();
console.log($scope.openListingsReport);
};
}
else {
// Sorry! No server-sent events support..
alert('SSE not supported by browser.');
}
}
I used the Django EventStream package and followed the example I do not seem to see any result in the angularjs. but in my
browser it gave me the error
EventSource's response has a MIME type ("text/html") that is not "text/event-stream". Aborting the connection.
I followed the example in https://github.com/fanout/django-eventstream.
Please how can I get django to send data to angularjs as it occurs
I developed a small prototype in django with one model: Profile, and 2 templates with 2 views (a list of profiles, and an edit profile page), with a form in forms.py. I want to test creating a PWA with Django and this is the additional things I did: 1) pip install django-progressive-web-app, 2) added 'pwa' to installed apps, 3) added a render view for the base.html that will be using the service worker!
def base(request):
return render(request,'app/base.html')
4) added it to the urls:
urlpatterns = [
path(r'', profiles, name="profiles"),
path('user/<pk>', profile, name="profile"),
path('', include('pwa.urls')),
]
5) added this to recognise the service worker:
PWA_SERVICE_WORKER_PATH = os.path.join(BASE_DIR, 'posts/static/js', 'serviceworker.js')
6) added the tags:
{% load pwa %}
<head>
...
{% progressive_web_app_meta %}
...
</head>
7) and added this to a serviceworker.js file, situated in the app/static/js:
var staticCacheName = 'djangopwa-v1';
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(staticCacheName).then(function(cache) {
return cache.addAll([
'/base_layout'
]);
})
);
});
self.addEventListener('fetch', function(event) {
var requestUrl = new URL(event.request.url);
if (requestUrl.origin === location.origin) {
if ((requestUrl.pathname === '/')) {
event.respondWith(caches.match('/base_layout'));
return;
}
}
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
What happened is that the service worker is running under Chrome developer tool, but in the django console it displays this error: Not Found: /base_layout, and the homepage is accessible through the Offline mode, but the other path (/user) isn't. And Google Chrome's console displays this error:
The FetchEvent for "http://localhost:8000/manifest.json" resulted in a network error response: the promise was rejected.
Promise.then (async)
(anonymous) # serviceworker.js:19
serviceworker.js:1 Uncaught (in promise) TypeError: Failed to fetch
Also, images are not being loaded.
What did I do wrong?
For the images, add the images url to the array passed to the cache.addAll method. Like so:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(staticCacheName).then(function(cache) {
return cache.addAll([
'/base_layout',
'/static/img-1.png',
'/static/img-2.png',
]);
})
);
});
To ensure your css and js files load, also add their paths to the array.
I'm working on a react-native-based mobile application and doing some operations with python in the background. I wanted to do both these transactions and connect to the database via Django rest api. But I get connection error.
I have used other rest-api and tried it. I also tried the rest api on the postman and it worked smoothly.
I tried everything, but I couldn't find a solution.
local rest url: http://localhost:8000/api/venues/
and fetch code:
componentDidMount() {
return fetch('http://localhost:8000/api/venues/?format=json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
also my django setting:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = [
'http://localhost:3030',
]
CORS_ORIGIN_REGEX_WHITELIST = [
'http://localhost:3030',
]
add these configurations after adding cors as middleware (change to your port number)
https://stackoverflow.com/a/69186898/12497001 provides a very good answer!
As mentioned in the Android Studio documentation, emulators use a special address network (https://developer.android.com/studio/run/emulator-networking.html).
To address requests to your own machine, you can use the address http://10.0.2.2
I am trying to implement navigation in Ionic 2. I have tried with DeepLinking and i got the result, but '#' sign is comming in URL.
When '#' sign will come in URL then Google Analytic will not recognize the website, that's why i have tried to implement navigation in different ways like Angular 2 Routing, that supports both (HTML5 or hash URL style), but unable to implement in Ionic 2.
Ex- http://localhost:8100/#/registration - This one working fine but i want without '#'.
Like http://localhost:8100/registration
Thanks for help
I put in a PR for #ionic/app-scripts 3.2.5 to remedy this:
https://github.com/ionic-team/ionic-app-scripts/pull/1545
In the meantime you can edit some project and dependency files to enable it:
src/app/app.module.ts:
IonicModule.forRoot(MyApp,
{
locationStrategy: 'path'
},
{
links: [
{ component: RegistrationPage, name: 'registration', segment: 'registration' },
{ component: LoginPage, name: 'login', segment: 'login' },
{ component: HomePage, name: 'home', segment: '' }
]
})
src/index.html:
<head>
...
<base href="/" />
...
</head>
node_modules/#ionic/app-scripts/dist/dev-server/http-server.js:
function createHttpServer(config) {
var app = express();
app.set('serveConfig', config);
app.get('/', serveIndex);
app.use('/', express.static(config.wwwDir));
app.use("/" + serve_config_1.LOGGER_DIR, express.static(path.join(__dirname, '..', '..', 'bin'), { maxAge: 31536000 }));
// Lab routes
app.use(serve_config_1.IONIC_LAB_URL + '/static', express.static(path.join(__dirname, '..', '..', 'lab', 'static')));
app.get(serve_config_1.IONIC_LAB_URL, lab_1.LabAppView);
app.get(serve_config_1.IONIC_LAB_URL + '/api/v1/cordova', lab_1.ApiCordovaProject);
app.get(serve_config_1.IONIC_LAB_URL + '/api/v1/app-config', lab_1.ApiPackageJson);
app.get('/cordova.js', servePlatformResource, serveMockCordovaJS);
app.get('/cordova_plugins.js', servePlatformResource);
app.get('/plugins/*', servePlatformResource);
if (config.useProxy) {
setupProxies(app);
}
app.all('/*', serveIndex);
return app;
}
The line app.all('/*', serveIndex); is what will redirect any 404 file or directory not found errors to index.html. The locationStrategy: 'path' setting can then work normally with deeplinks and redirects under these circumstances.
Try to use pathLocationStrategy instead of HashLocationStrategy.
Add this in app.module.ts
import { LocationStrategy,
PathLocationStrategy } from '#angular/common';
...
#NgModule({
...
providers: [
{
provide: LocationStrategy,
useClass: PathLocationStrategy
},
...
Or other way is
IonicModule.forRoot(MyApp, {
locationStrategy: 'path'
})
And make sure to have a valid base href.
So here is the list of things which I did. Hope this helps.
We need to remove # in path of every url because Google Analytics rejects the urls with # in them. In App Module , add {locationStrategy: 'path'} to your App Module as follows :
IonicModule.forRoot(MyApp, {
locationStrategy: 'path'
})
2 .Now # is removed from the url. But when you refresh or directly access the url, this wont work because this is expected behaviour for any SPA. When you refresh the page , server tried to find the page at the location mentioned. As stated by #Parth Ghiya above For eg: if you hit localhost/abc , then server tries to find abc/index.html which actually doesn't exist.So to resolve this , you have wrote configurations on my server i.e to point every request to index.html . I am using node express server to deploy the app. Use the following code to route every request to index.html -
var express = require('express');
var path = require('path')
var app = express();
app.use(express.static(path.resolve(__dirname, "www")));
app.use('/*', function(req, res){
res.sendFile(__dirname+ '/www' + '/index.html');
});
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), function() {
console.log("listening to Port", app.get("port"));
});