React admin-on-rest adding X-Total-Count - reactjs

I'm using admin-on-rest but getting an error when trying to connect to github api
Error:
The X-Total-Count header is missing in the HTTP Response. The jsonServer REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?
and
Warning: Missing translation for key: "The X-Total-Count header is missing in the HTTP Response. The jsonServer REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?"
I'm trying to add the X-Total-Count header but then got a new error
render() {
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({Accept: 'application/json'});
}
// add your own headers here
options.headers.set('X-Total-Count', '32');
return fetchUtils.fetchJson(url, options);
}
const restClient = jsonServerRestClient('https://api.github.com', httpClient);
return (
<Admin restClient={restClient}>
<Resource name="users" list={PostList}/>
</Admin>
);
}
Failed to load https://api.github.com/users?_end=10&_order=DESC&_sort=id&_start=0: Request header field x-total-count is not allowed by Access-Control-Allow-Headers in preflight response.

At your backend API function need to get X-Total-Count and set it to Response Header
Example:
exports.findAll = (req, res) => {
var total = Data.countAll()// your count all function
Data.findAll({ where: condition })
.then(data => {
res.set('Access-Control-Expose-Headers', 'X-Total-Count')
res.set('X-Total-Count', total)
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving data."
});
});
};

As kunal pareek said, this header must be part of the response, not the request for this jsonRestClient.
You'll have to create a custom restClient specific to the github api.
Please read https://marmelab.com/admin-on-rest/RestClients.html#writing-your-own-rest-client.

Related

How to get request headers for the Apollo GraphQL error?

I need to get the request header on the client when an error occurs
const { data, error } = useQuery(gql`Query ...`);
// ..
if (error) {
// get the request headers here
// e.g. error.graphQLErrors[0].headers.requestId
}
I was trying to modify the error using onError link but this object is Read Only
import { onError } from '#apollo/client/link/error';
const errorLink = onError((errorHandler) => {
errorHandler.graphQLErrors[0].extensions = { requestId: ... }
})
I know I can extend extensions on the backend side but I need to generate the request ID on the client side.
There's an example similar to what you're describing on the Apollo docs. It doesn't use extensions specifically, but would enable you to generate the request ID mentioned.

It was set headers and axios but Why happen cros error?

Premise / What you want to achieve
React x Redux (port: 3000)
Go (port: 8080)
I am making a SPA.
I run into a CROS error when hitting the Go API.
I've encountered this problem many times, and every time I think it's solved, I hit a new API.
I should have made the basic settings, but I'm in trouble because I don't know what caused it.
We would appreciate it if you could help us.
Problem / Error message
Access to XMLHttpRequest at'http://localhost:8080/login' from origin'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No'Access-Control -Allow-Origin'header is present on the requested resource.
I encountered this when I hit the login API (post).
However, when I encountered this problem several times, I set cros on the header of api and axios side, and
Another get API avoided the error.
Also, when you hit api with postman, it becomes header
We have also confirmed that the header set in Go such as Allow-Origin is given without any problem.
Applicable source code
Header settings in Go
w.Header (). Set ("Content-Type", "application /json")
w.Header (). Set ("Access-Control-Allow-Origin", "http://localhost:3000")
w.Header (). Set ("Access-Control-Allow-Credentials", "true")
react axios settings
axios.defaults.baseURL ='http://localhost:8080';
axios.defaults.headers.post ['Content-Type'] ='application/json';
Posting code with an error
export const signIn = (email, password) => {
return async (dispatch) => {
try {
const response = await axios.post ('/login', {
email: email,
password: password,
});
const data = response.data;
dispatch (
signInAction ({
isSignedIn: true,
})
);
} catch (error) {
console.log (error);
}
};
};
Code hitting a successful getapi
useEffect (() => {
async function fetchTickers () {
try {
const response = await axios.get (`/ticker?Symbol=^skew`);
const data = response.data;
setChartAry ([... chartAry, [... data.daily]]);
} catch (error) {
console.log (error);
setChartAry ([]);
}
}
fetchTickers ();
}, []);
What I tried
I tried all the solutions that hit with stackoverflow etc. Also, considering the possibility of a problem with the browser itself, we also cleared the cache.
Is it the difference between axios by get and post? And how should I debug it?
I had this problem some time ago but I used Express for the backend, who knows this can solve your problem too.
try adding this to the axios settings axios.defaults.withCredentials = true;
You also need to allow the OPTIONS method for preflight requests
this article might help you solve the CORS problem on the backend: https://flaviocopes.com/golang-enable-cors/
The method was validated in gorilla / mux.
- r.HandleFunc("/login", app.loginHandler).Methods("POST")
+ r.HandleFunc("/login", app.loginHandler).Methods("POST", "OPTIONS")
We also had to deal with preflight.
if r.Method == "OPTIONS" {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.WriteHeader(http.StatusOK)
return
}

JavaScript CORS error when uploading files with Axios

I am developing a web application with Flask on the backend and React and Redux on the frontend.
I want to add a "Change Profile Picture" option to the profile page but whenever I make a post request with axios to my /api/user/upload_image/ route, i get the following errors:
Access to XMLHttpRequest at 'http://localhost:5000/api/user/update_image' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
PATCH http://localhost:5000/api/user/update_image net::ERR_FAILED
Which is weird becuase I have set up my CORS wrapper in my Flask app like so:
self.cors = CORS(self.app, resources={r"/api/*": {"origins": "*"}})
which should allow requests to /api/ from all origins.
I also tried to do the same thing with Postman and it worked like a charm - uploaded the file and saved it to /server/public/profile_pictures/
When i try to upload regular JSON text from my react application it works as well. It bugs out on file uploads only.
Here is the JSX for the input + the event handler
<label>
Change Profile Picture
<input onChange={(e) => {
this.setState({image: e.target.files[0]})}
} type="file" name="image" />
</label>
Then i have a submit button which dispatches the following action with this.state.image as a parameter:
export const updateImage = (file) => {
return async (dispatch, getState) => {
const formData = {
user_id: getState().currentUser.user.user_id,
auth_key: getState().currentUser.auth_key,
image: file
}
Axios.patch("http://localhost:5000/api/user/update_image", formData, {
headers: {
'Content-Type' : 'multipart/form-data'
}
})
.then(response => {
dispatch({type: UPDATE_IMAGE, payload: response.data})
})
}
I tried using the built in formData method to create the JS object too but that was no good either.
Finally here is the python method which is called when the /api/user/update_image route is hit:
def update_image(self, request):
image = request.files['image']
data = request.params
image.save("./public/profile_pictures/user_p_picture_id_"+data['user_id']+".jpg")
fsql.update("""UPDATE users SET profile_picture = %s WHERE user_id = %s""", ("/public/profile_pictures/user_p_picture_id_"+data['user_id']+".jpg", data['user_id']))
return jsonify({
"error_code" : "200",
"error_message" : "Success"
})
I actually solved this about a week and a half ago but I checked the status today.
So the solution was to make a few changes to my config parameter and CORS parameters. Here is the configs i am using right now:
config = {
'ORIGINS': [
'http://localhost:3000', # React
'http://127.0.0.1:3000', # React
],
'SECRET_KEY': '...' #secret key
self.cors = CORS(self.app, resources={
r'/api/*': {
"Access-Control-Allow-Origin": config["ORIGINS"],
"Access-Control-Allow-Credentials": True,
'supports_credentials': True
},
},
supports_credentials = True,
expose_headers = "*"
)
self.app.config['UPLOAD_FOLDER'] = r'/*' # Change this to only the folder you want to save images to
self.app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # Change this according to your file size
This solved my CORS and file transport issues.
I really hope this helps someone. The CORS docs on flask-cors do not cover everything in regards to file uploading and session storage so we kind of have to solve the errors without knowing how everything works - like trying to solve a puzzle with missing pieces.
HMU in messages if you have any good tools for CORS in flask which are well documented and have a community around them.

POST JSON with iron-ajax to SQL Server with Node

I am trying to return user data from a login with Polymer. I have it working with Postman, but am having trouble translating it into Polymer.
In Postman this returns a JSON object, but in Polymer it is returning undefined.
Polymer Client Code [Connecting to node.js server]
<iron-ajax id="ajaxUser"
url="http://localhost:8080/login"
method="post"
handle-as="json"
content-type="application/json"
headers='{"Access-Control-Allow-Origin": "*"}'
params="[[params]]"
on-response="saveUserCredentials"
last-response="{{user}}"></iron-ajax>
...
<paper-input id="username"></paper-input>
<paper-input id="password"></paper-input>
<paper-button on-tap="loginUser"></paper-button>
...
loginUser() {
this.params = {"username": this.$.username.value, "password": this.$.password.value};
console.log(this.params); // logs this.params as populated JSON
let request = this.$.ajaxUser.generateRequest();
request.completes.then(req => {
console.log(req); // logs <iron-request></iron-request>
console.log(this.user); // logs []
})
.catch(rejected => {
console.log(rejected.request); // not returned
console.log(rejected.error); // not returned
})
}
saveUserCredentials() {
console.log(this.user);
}
Node, Express, mssql Server Code [Connecting to SQL Server database]
app.post("/login", (req, res) => {
session.login(req, res)
})
...
exports.login = (req, res) => {
sql.connect(config.properties)
.then(pool => {
pool.request()
.input('user', sql.VarChar(50), req.body.username)
.input('password', sql.VarChar(50), req.body.password)
.query("SELECT role FROM Login WHERE username = #user AND password = #password")
.then(response => res.send(response))
.catch(err => res.send(err))
})
}
Error
SyntaxError: Unexpected token # in JSON at position 0 .
at JSON.parse ()
at createStrictSyntaxError (C:\node_modules\body-parser\lib\types\json.js:157:10)
at parse (C:\node_modules\body-parser\lib\types\json.js:83:15)
at C:\node_modules\body-parser\lib\read.js:121:18 .
at invokeCallback (C:\node_modules\raw-body\index.js:224:16)
at done (C:\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (C:\node_modules\raw-body\index.js:273:7)
at IncomingMessage.emit (events.js:159:13)
at endReadableNT (_stream_readable.js:1062:12)
at process._tickCallback (internal/process/next_tick.js:152:19)
The first issue appears to be that your server is expecting a JSON object in the request, but the server sees the request as a string due to a missing Content-Type header on your request. To set the Content-Type for JSON requests, set <iron-ajax>.contentType to application/json:
<iron-ajax content-type="application/json" ...>
OK, I was able to get a server response by setting content-type=application/json as an iron-ajax property. Am now getting Unexpected token # in JSON at position 0 as a server side error...
That sounds like the request is not actually valid JSON (since it contains a # as the first character). Use the Chrome DevTools Network Panel to inspect the actual contents of the payload. I wouldn't rely solely on console.log in your code.
Also, it is now making two requests when I submit. One with the content-type set, which resolves to 200, and one with that resolves to 400 with parsing error.
The first message is likely the preflight request, which is sent (as part of CORS) to the server to check whether content-type="application/json" is an allowed header. The second message is the intended data request, but that fails with the following error.
And a client side error of No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4001' is therefore not allowed access. The response had HTTP status code 400.
Your server needs to enable CORS requests. There are various ways to accomplish this, but the simplest Node solution might be to use the cors package:
const cors = require('cors');
const app = express();
app.use(cors());

Multiple file uploads to Cloudinary with Axios in React

I have tried implementing the superagent way of uploading multiple files in axios. But somehow, I'm getting an error in console
Failed to load https://api.cloudinary.com/v1_1/xxxx/image/upload:
Request header field Authorization is not allowed by
Access-Control-Allow-Headers in preflight response.
My upload handler looks like this
uploadFile(){
const uploaders = this.state.filesToBeSent.map(file => {
const formData = new FormData();
formData.append("file", file);
formData.append("upload_preset", "xxxxx");
formData.append("api_key", "xxxxx");
formData.append("timestamp", (Date.now() / 1000) | 0);
return axios.post(url, formData, {
headers: { "X-Requested-With": "XMLHttpRequest" },
}).then(response => {
const data = response.data;
const fileURL = data.secure_url
console.log(data);
})
});
// Once all the files are uploaded
axios.all(uploaders).then(() => {
// ... perform after upload is successful operation
console.log("upload completed ", uploaders);
});
}
I have got this example from here
Another thing is confusing to me. In superagent we can attach parameters to the request field which includes API Secret Key of Cloudinary like this:
const paramsStr = 'timestamp='+timestamp+'&upload_preset='+uploadPreset+secretKey;
const signature = sha1(paramsStr);
const params = {
'api_key': 'xxxx',
'timestamp': timestamp,
'upload_preset': uploadPreset,
'signature': signature
}
Object.keys(params).forEach(key => {
uploadRequest.field(key, params[key])
});
But in that example, it is not mentioned how to append the secret key and other params to axios.
You will need to generate the signature on your backend, and then perform the upload with the generated signature.
You can generate a signature via the following instructions- https://support.cloudinary.com/hc/en-us/articles/203817991-How-to-generate-a-Cloudinary-signature-on-my-own-
You can also take a look at the following example on how to append the signature to your request. It's in PHP, however, the guidelines still apply.
https://gist.github.com/taragano/a000965b1514befbaa03a24e32efdfe5

Resources