I am having issues with making a simple fetch call using React to my Flask backend. I am using the componentDidMount lifecycle but keeps receiving a CORS issue. I have tried using CORS from flask_cors but still cannot get it. Help!
I have also tried adding proxy with the url to the backend in my package.json but still did not help.
React:
class App extends Component {
state = {
flights: []
}
componentDidMount(){
fetch('http://localhost:5000/flights')
.then(res => console.log(res))
.catch(err => console.log(err))
}
flask:
from flask_cors import CORS, cross_origin
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
import json
import random
import string
def get_confirmation_number():
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))
def flights(request):
with open('flights.json') as f:
content = json.loads(f.read())
return content
def book(request):
if random.randint(0,100) < 20:
return {
"success": False,
"message": "This flight is full."
}
else:
errors = []
try:
if 'first_name' not in request.json:
errors.append({
"field": "first_name",
"error": "is_required",
})
if 'last_name' not in request.json:
errors.append({
"field": "last_name",
"error": "is_required",
})
except:
errors.append({
"field": "all",
"error": "empty_request"
})
if not errors:
return {
"success": True,
"confirmation": get_confirmation_number()
}
else:
return {
"success": False,
"message": "You did not pass a valid request.",
"errors": errors,
}
if __name__ == '__main__':
with Configurator() as config:
config.add_route('flights', '/flights')
config.add_view(
flights, route_name='flights', renderer='json'
)
config.add_route('book', '/book')
config.add_view(
book, route_name='book', renderer='json'
)
app = config.make_wsgi_app()
CORS(app)
print('Servers on http://0.0.0.0:5000')
server = make_server('0.0.0.0', 5000, app)
server.serve_forever()
Ideally I would like to solve this on the front end and not have to use flask_cors, but if it is necessary I am open to that as well.
I got the same issue with the same stack but use CORS(app) solve this. It's probably a problem with make_wsgi_app()
You can try this:
server = make_server('0.0.0.0', 5000, app)
CORS(server)
server.serve_forever()
Related
So basicaly I want to fetch the data from Laravel server to next js api server and this seems to be working fine for the other atributes like title but the image is not fetching and return error 500 and 'ECONNREFUSED'
Here is the code for courses inside the api colder pages/api/courses.ts
import { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
import Course from "../../models/course";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const courses = await Course.fetchAll();
res.status(200).json(courses);
}
Code for the api route on laravel
Route::get('/courses', function () {
$courses = Courses::all();
// allow to remote access
header('Access-Control-Allow-Origin: *');
return response()->json(['courses' => $courses], 200);
});
Code for the API call
const fetchCourses = async () => {
const courses = await axios.get("http://localhost:3000/api/courses", {
headers: {
"Content-Type": "application/json",
// allow cors
"Access-Control-Allow-Origin": "*",
},
});
setCourses(courses.data);
};
The image appears like that
The error that appears on image url
I fixed it by replacing the NextImage tag with normal image tag and it worked
I have created a custom route in Strapi v4 called "user-screens". Locally I hit it with my FE code and it returns some data as expected. However when I deploy it to Heroku and attempt to access the endpoint with code also deployed to Heroku it returns a 404. I've tailed the Heroku logs and can see that the endpoint is hit on the server side, but the logs don't give anymore info other than it returned a 404.
I am doing other non custom route api calls and these all work fine on Heroku. I am able to auth, save the token, and hit the api with the JWT token and all other endpoints return data. This is only happening on my custom route when deployed to Heroku. I've set up cors with the appropriate origins, and I am wondering if I need to add something to my policies and middlewares in the custom route. I have verified the permissions and verified the route is accessible to authenticated users in the Strapi admin.
Here is my route:
module.exports = {
routes: [
{
method: "GET",
path: "/user-screens",
handler: "user-screens.getUserScreens",
config: {
policies: [],
middlewares: [],
},
},
],
};
And my controller:
"use strict";
/**
* A set of functions called "actions" for `user-screens`
*/
module.exports = {
getUserScreens: async (ctx) => {
const user = ctx.state.user;
if (!user) {
return ctx.badRequest(null, [
{ messages: [{ id: "No authorization header was found" }] },
]);
}
strapi.entityService
.findMany("api::screen.screen", {
owner: user.id,
populate: ["image"],
})
.then((result) => {
ctx.send(result);
});
},
};
For anyone facing this, the answer was to change how I returned the ctx response from a 'send' to a 'return' from the controller method. I am not sure why this works locally and not on Heroku, but this fixes it:
New controller code:
module.exports = {
getUserScreens: async (ctx) => {
const user = ctx.state.user;
if (!user) {
return ctx.badRequest(null, [
{ messages: [{ id: "No authorization header was found" }] },
]);
}
return strapi.entityService
.findMany("api::screen.screen", {
owner: user.id,
populate: ["image"],
})
.then((result) => {
return result;
})
.catch((error) => {
return error;
});
},
};
In the test/posts/posts.e2e-spec.ts file
import { INestApplication } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Test, TestingModule } from '#nestjs/testing';
import request = require('supertest');
import { PostsModule } from '../../src/posts/posts.module';
describe('Posts (e2e)', () => {
const posts = {
id: 1,
name: 'FirstPost #1',
};
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
...
}),
PostModule,
],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
describe('post', () => {
it('should retrieve all post data', async () => {
request(app.getHttpServer())
.post('/graphql')
.send({
query:
`{findPosts() {
name
}}`,
})
.expect(200)
.expect((res) => {
console.log(res.body.data)
expect(res.body.data.post.length).toEqual(posts.length)
})
})
})
});
I created migration and inserted data into database first, then run this test, it can't go to the expect items. Even set console log I can't see anything in the output.
So maybe the /graphql can't be access in this way? I can access the endpoint from browser as http://localhost:3000/graphql.
If import supertest as
import * as request from 'supertest';
In the line request it showed:
This expression is not callable. Type ‘typeof supertest’ has no call signatures.
The version of them:
supertest: 6.1.3
#types/supertest: 2.0.11
Check out this very useful link https://github.com/jmcdo29/testing-nestjs/tree/main/apps/graphql-sample. It explains a lot of things regarding tests including graphql nestjs testing along with sample application
I am using fastify to proxy calls to spring boot backend. Using fastify-http-proxy as proxy and application/x-www-form-urlencoded content type. To support it I am using fastify-formbody.
If I do direct call to spring boot back end, I see request like
parsedFormData=FormData{values={foo=[io.undertow.server.handlers.form.FormData$FormValueImpl#7848eda9], bar=[io.undertow.server.handlers.form.FormData$FormValueImpl#22f0cd6c]}}
But when I do call with proxy, my request is like (quotes are added for values)
parsedFormData=FormData{values={"foo=[io.undertow.server.handlers.form.FormData$FormValueImpl#7848eda9], bar=[io.undertow.server.handlers.form.FormData$FormValueImpl#22f0cd6c]}}
My proxy looks like this:
import { FastifyHttpsOptions, FastifyReply, FastifyRequest } from 'fastify';
import fastifyHttpProxy from 'fastify-http-proxy';
import * as qs from 'qs';
export class ProxyRoute {
public registerProxy(app, prefix: string, rewritePrefix: string) {
if (app.conf == undefined) {
app.decorate('conf', {});
}
app.register(fastifyHttpProxy, {
contentTypesToEncode: ['application/x-www-form-urlencoded'],
upstream: '',
prefix: prefix,
rewritePrefix: rewritePrefix,
replyOptions: {
getUpstream: () => app.conf.hostUrl,
rewriteRequestHeaders: (_req: FastifyRequest, headers: FastifyHttpsOptions<any>) => ({
...headers,
sessionID: app.conf.sessionID,
}),
},
preHandler: async (req: FastifyRequest, res: FastifyReply) => {
if (contentType && contentType.includes('application/x-www-form-urlencoded')) {
req.body = qs.stringify(req.body);
}
},
proxyPayloads: false,
});
}
}
The issue was with proxyPayload parameter. It should be removed.
Link to discussion on git.
I made a register page that use restClient to send a POST to /users api.
But my problem is that the only way to send a POST is to be logged first as I receive this error log from the restClient :
'Could not find stored JWT and no authentication strategy was given'
Is there a way to desactivate the authentication middleware for a specific api call ?
// registerActions.js
import { CREATE } from 'admin-on-rest'
export const USER_REGISTER = 'AOR/USER_REGISTER'
export const USER_REGISTER_LOADING = 'AOR/USER_REGISTER_LOADING'
export const USER_REGISTER_FAILURE = 'AOR/USER_REGISTER_FAILURE'
export const USER_REGISTER_SUCCESS = 'AOR/USER_REGISTER_SUCCESS'
export const userRegister = (data, basePath) => ({
type: USER_REGISTER,
payload: { data: { email: data.username, ...data } },
meta: { resource: 'users', fetch: CREATE, auth: true },
})
//registerSaga.js
import { put, takeEvery, all } from 'redux-saga/effects'
import { push } from 'react-router-redux'
import { showNotification } from 'admin-on-rest'
import {
USER_REGISTER,
USER_REGISTER_LOADING,
USER_REGISTER_SUCCESS,
USER_REGISTER_FAILURE
} from './registerActions'
function* registerSuccess() {
yield put(showNotification('Register approved'))
yield put(push('/'))
}
function* registerFailure({ error }) {
yield put(showNotification('Error: register not approved', 'warning'))
console.error(error)
}
export default function* commentSaga() {
yield all([
takeEvery(USER_REGISTER_SUCCESS, registerSuccess),
takeEvery(USER_REGISTER_FAILURE, registerFailure),
])
}
You'll probably have to make your own feathers client and explicitly bypass the call to authenticate for this specific request
You can also write a rest wrappper this will intercept the call for this particular case and bypass auth
https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload
So something like below
const restWrapper = requestHandler => (type, resource, params) => {
import { fetchUtils } from 'admin-on-rest';
if (type === 'CREATE' && resource === 'users') {
return fetchUtils.fetchJson(url, params)
.then((response) => {
const {json} = response;
return { data: json };
})
}
Eliminates the need of rewriting an entire Rest Client when you only want to override the default behaviour for a single case