Fetch content from API - python

My frontend (ReactJS) is located at localhost:3000 which sends a request to my backend (localhost:5090/api/fetch/<name>)
frontend-snippet:
handleSubmit(event) {
//alert('A name was submitted: ' + this.state.value);
fetch('http://127.0.0.1:5090/api/fetch/' + this.state.value,
{
mode: 'no-cors'
}).then((response) => console.log(response));
event.preventDefault();
}
the backend receives the request:
127.0.0.1 - - [22/Oct/2020 10:54:44] "GET /api/fetch/212 HTTP/1.1" 200 -
and responses with {"stock": name}
Python
def get(self, name):
print(name)
return {"stock": name}
however, i'm unable to get the response.
What am I missing, that I can actualy see the response data of {"stock": <name>}?

Sending a request with no-cors returns an opaque type object.
Updating my backend to allow all sources
What happens with cross-origin requests from frontend JavaScript is that browsers by default block frontend code from accessing resources cross-origin. If Access-Control-Allow-Origin is in a response, then browsers will relax that blocking and allow your code to access the response.
from flask_cors import CORS
...
CORS(app, resources={r"/api/*": {"origins": "*"}})
and then removing the mode to cors in frontend
fetch('http://127.0.0.1:5090/api/fetch/' + this.state.value,
{
}).then(response => response.json())
.then(response => {
console.log(response)
})
.catch(error => {
console.log('Error ' + error);
})
successfully displays the data
(response)
{stock: "111"}

Can you try like this
.then(response => response.json())
.then(result => {
console.log(result);
})
})
.catch(error => {
console.log('Error ' + error);
})

code in Ejaz's answer should work just fine, But I'd recommned you to read the official documentation for fetch api
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
You cant just console.log the response from fetch api it just returns a promise,
you cant print response.body either as it returns a readable stream, Use interface methods on body to read the stream into completion.
You can call response.text() or response.json() depending on type of data your api returns.
Using fetch api, you have to deal with promises, I'll try to refactor your handleSubmit function using async/await, much cleaner way to deal with promises.
async handleSubmit(event) {
event.preventDefault();
try{
let response = await fetch('http://127.0.0.1:5090/api/fetch/'+this.state.value, {
mode: 'no-cors'});
console.log(await response.json());
}
catch(error => console.log('Error ' + error));
}

Related

flask_jwt_extended.exceptions.NoAuthorizationError: Missing Authorization Header

Server-side flask
#project_ns.route('/projects')
class ProjectsResource(Resource):
#project_ns.marshal_list_with(project_model)
#jwt_required()
def get(self):
"""Get all projects """
user_id = User.query.filter_by(username=get_jwt_identity()).first() # Filter DB by token (username)
projects=Project.query.filter_by(user_id=user_id)
#projects = Project.query.all()
return projects
client-side reactjs
const getAllProjects=()=>{
const token = localStorage.getItem('REACT_TOKEN_AUTH_KEY');
console.log(token)
const requestOptions = {
method: 'GET',
headers: {
'content-type': 'application/json',
'Authorization': `Bearer ${JSON.parse(token)}`
},
body: "Get projects listed"
}
fetch('/project/projects', requestOptions)
.then(res => res.json())
.then(data => {
setProjects(data)
})
.catch(err => console.log(err))
}
I specified header on the client side and the error still occurs:
flask_jwt_extended.exceptions.NoAuthorizationError: Missing Authorization Header
my flask versions are as follows:
Flask==2.0.1
Flask-Cors==3.0.10
Flask-JWT-Extended==4.2.3
Flask-Migrate==3.1.0
Flask-RESTful==0.3.9
flask-restx==0.5.0
Flask-SQLAlchemy==2.5.1
I have tried many options and the issue is still persisting. Would love to come to a resolution. Thanks in advance!
I haven't used these libraries before, but it sounds like it might possibly be an issue with the Flask-RESTful library?
https://stackoverflow.com/a/52102884/2077884
https://github.com/vimalloc/flask-jwt-extended/issues/86#issuecomment-335509456
https://github.com/vimalloc/flask-jwt-extended/issues/86#issuecomment-444983119
If you're not getting a value for console.log(token), I would start there. And maybe check to see if you can decode the token details via https://jwt.io/ to ensure that the value you have for token is valid.

How to send Authorization Header through Swagger UI using FastAPI?

In the frontend, I have the following JS function:
export const uploadFormData = async (
token: string,
email: string,
formInfo: Array<Object>,
): Promise<any> => {
const formData = new FormData();
formData.append('email', email);
formData.append('form_info', JSON.stringify({ formInfo }));
return fetch(
`${process.env.ENDPOINT}/upload_form_data/`,
{
method: 'POST',
headers: {
Authorization: `Token ${token}`,
},
body: formData,
},
).then((response) => {
console.log(response.body?.getReader());
if (response.status === 404) {
throw Error('Url not found');
}
if (response.status === 422) {
throw Error('Wrong request format');
}
if (response.status !== 200) {
throw Error('Something went wrong with uploading the form data.');
}
const data = response.json();
return {
succes: true,
data,
};
}).catch((error) => Promise.reject(error));
};
which sends a POST request to the following endpoint in the FastAPI backend:
#app.post("/api/queue/upload_form_data/")
async def upload_form_data(
email: str = Body(...),
form_info: str = Body(...),
authorization: str = Header(...),
):
return 'form data processing'
However, it keeps throwing the following errors:
In the frontend:
POST http://localhost:8000/api/queue/upload_form_data/ 422 (Unprocessable Entity)
Uncaught (in promise) Error: Wrong request format
In the backend:
POST /api/queue/upload_form_data/ HTTP/1.1" 400 Bad Request
In Swagger UI (response body):
{
"detail": [
{
"loc": [
"header",
"authorization"
],
"msg": "field required",
"type": "value_error.missing"
}
]
}
What is wrong with the request that is causing these errors?
In Swagger/OpenAPI specification, Authorization is a reserved header, along with Accept and Content-Type headers as well for Swagger's built-in authentication/authorization functionality—see Swagger documentation; hence, they are not allowed to be defined. If you are using Swagger, you can't have Authorization defined along with your endpoint's parameters, as it will be ignored when submitting the request through Swagger UI, and you'll get a 422 Unprocessable Entity error with a body message saying that the authorization header is miising (just like the error posted in your question).
Solutions
If you don't need Swagger UI for testing your application, you can leave it as is and keep using JavaScript Fetch API, passing the Authorization in the headers. Also, note that you don't really have to define any Header parameters in your endpoint, as you can always access them through the Request object, for instance:
from fastapi import Request
#app.post('/')
def main(request: Request):
token = request.headers.get('authorization')
return token
If you do need this to work with Swagger UI as well, one solution would be to rename the authorization Header parameter to something else, e.g., token: str = Header(...). Then, inside your endpoint check if the API key is in either the token or request.headers.get('authorization')—if both result to None, then it means no Authorization header was provided. Otherwise, use FastAPI's HTTPBearer, which would allow you to click on the Authorize button on the top right hand corner of your screen in Swagger UI autodocs at /docs, where you can type your API key in the Value field. This will set the Authorization header in the request headers. Example:
from fastapi.security import HTTPBearer
security = HTTPBearer()
#app.get('/')
def main(authorization=Depends(security)):
return authorization.credentials
Alternatively, you could use APIKeyHeader
from fastapi.security.api_key import APIKeyHeader
from fastapi import Security
api_key = APIKeyHeader(name='Authorization')
#app.get('/')
def main(token = Security(api_key)):
return token

Aws Websocket {"message":"Missing Authentication Token"}

anyone knows what's wrong with this code.
The address from the api gateway returns {"message": "Missing Authentication Token"}.
All code deploy by serverless framework on AWS.
JS custom.js
var socket;
// Connect to the WebSocket and setup listeners
function setupWebSocket(username, token) {
socket = new ReconnectingWebSocket(" {api endpoint}?token=" + token);
socket.onopen = function(event) {
data = {"action": "getRecentMessages"};
socket.send(JSON.stringify(data));
};
socket.onmessage = function(message) {
var data = JSON.parse(message.data);
data["messages"].forEach(function(message) {
if ($("#message-container").children(0).attr("id") == "empty-message") {
$("#message-container").empty();
}
if (message["username"] === username) {
$("#message-container").append("<div class='message self-message'><b>(You)</b> " + message["content"]);
} else {
$("#message-container").append("<div class='message'><b>(" + message["username"] + ")</b> " + message["content"]);
}
$("#message-container").children().last()[0].scrollIntoView();
});
};
}
// Sends a message to the websocket using the text in the post bar
function postMessage(token){
var content = $("#post-bar").val();
if (content !== "") {
data = {"action": "sendMessage", "token": token, "content": content};
socket.send(JSON.stringify(data));
$("#post-bar").val("");
}
}
handler.py
def _send_to_connection(connection_id, data, event):
gatewayapi = boto3.client("apigatewaymanagementapi",
endpoint_url="https://" + event["requestContext"]["domainName"] +
"/" + event["requestContext"]["stage"])
return gatewayapi.post_to_connection(ConnectionId=connection_id,
Data=json.dumps(data).encode('utf-8'))
Contrary to the message, the issue is not actually a missing authentication token. API Gateway returns the same message when the endpoint you are accessing is not exactly correct; i.e. does not exist, probably due to some typo or slight misconfiguration. I would suggest confirming that your endpoint is valid and re-check that.
The reason you get this message is because if they returned a 404 it meant that you now know that the (invalid) endpoint you called does not exist. But that also means that you could do a brute force process of checking all possible endpoints and any not returning 404 do exist but behind some kind of firewall, authentication system or API Key. By returning 403 for all endpoints, even if they don't exist, AWS are improving their security posture. Its the same reason that on a login form you don't return a message such as "Username does not exist", because otherwise someone could find a way to find valid usernames based on your error message.
Hope that helps

How do I fix this axios GET request? Keep getting 404 status code

Trying to get json data to front end and have tried a bunch of versions of axios requests but keep getting 404 status code.
This is an example of the front end format:
class App extends Component {
constructor () {
super();
this.state = {
message: ''
};
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
axios.get('./hello')
.then(response => {
this.setState({ message: response.data.text });
})
.catch(error => {
console.log(error);
});
}
render () {
return (
<div className="button-container">
<button className='button' onClick={this.handleClick}>Click Me</button>
<p>{this.state.message}</p>
</div>
)
}
}
and back end routing:
#app.route('/hello')
def hello_world():
return jsonify(text='hello world')
Error message says 'Failed to load resource: the server responded with a status of 404 (Not Found)' or says http://localhost:5003/hello doesn't exist
First check your server, which url and port, your api is exposed
You need to pass complete url to axios constructor otherwise it will send request to same origin/url where your client is hosted, .e.g webapp at localhost:3000.
So your code will be
const SERVER_URL = 'http:localhost:5000'
axios.get(`${SERVER_URL}/hello`)

Node JS and Python - POST image from Node JS to Python REST API

I have a Node JS application. I want to send an image from the Node JS application to a REST API which is written in Python. The key and the inputs needed by the Python REST API are as follows
My problem is that I am able to POST a simple 'Hello World' string with the code I have written and get a response. However, when I try to send an image something goes wrong and I get no response.
var http = require('http');
var querystring = require('querystring');
// This is some dummy string data
var postData = querystring.stringify({
msg: 'hello world'
});
var fs = require('fs')
, path = require('path')
, certFile = path.resolve(__dirname, 'ssl/client.crt')
, keyFile = path.resolve(__dirname, 'ssl/client.key')
, caFile = path.resolve(__dirname, 'ssl/ca.cert.pem')
, request = require('request');
// I want to send an image from one server to another. What changes should I make to the options below for POSTing image data
var options = {
hostname: '127.0.0.1',
port: 8888,
path : '/predict',
//image: fs.createReadStream('car.jpg'), //Should I give something like this??
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Content-Length': postData.length
}
};
var req = http.request(options, function (res) {
console.log('STATUS:', res.statusCode);
console.log('HEADERS:', JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY:', chunk);
});
res.on('end', function () {
console.log('No more data in response.');
});
});
req.on('error', function (e) {
console.log('Problem with request:', e.message);
});
req.write(postData);
req.end();
Please let me know what changes I have to make to this code to post an image.I read about the use of multer package. However, the examples that I came across were using JS on both ends. Since for me, I have a Python REST API , I cannot use that. PLease help since I have been struggling with it for some time now.
Edit 1: Based on #Jana's suggestion, I added the multipart within the options and tried, where image is the key and the value is fs.createReadStream('car.jpg') . However, at the python end, it does not get the 'image' key because of which I get a False response. What am I missing?
var options = {
hostname: '127.0.0.1',
port: 8888,
path : '/predict',
//image: fs.createReadStream('car.jpg'), //Should I give something like this??
multipart: [
{
'content-type': 'application/json',
body: JSON.stringify({'image': fs.createReadStream('car.jpg') })
}
],
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
//'Content-Length': postImageData.length
}
};
Check this,
`request({
method: 'POST',
uri: 'http://127.0.0.1:8888/predict',
multipart: [{
'content-type': 'application/json',
body: JSON.stringify({
"key": "value"
})
},
{
body: fs.createReadStream('car.jpg')
}
],
},
function(error, response, body) {
if (error) {
return console.error('upload failed:', error);
}
console.log('Upload successful! Server responded with:', body);
})`
And also you can get the best examples from its own documentation Request - Simplified HTTP client

Categories

Resources