contentful.js
contentful.js copied to clipboard
How to access headers on 429 Responses?
Expected Behavior
On error, with retryOnError
set to false, when I hit the rate limit, I would expect to receive an error that exposes the rate-limit metadata referenced here.
Actual Behavior
The error that is sent back is a JS error with string fields that do not include the headers that offer the metadata about how long to wait.
{
"status": 429,
"statusText": "Too Many Requests",
"message": "You have exceeded the rate limit of the Organization this Space belongs to by making too many API requests within a short timespan. Please wait a moment before trying the request again.",
"details": {},
"request": {
"url": "<ENTRY URL>",
"headers": {
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/vnd.contentful.management.v1+json",
"X-Contentful-User-Agent": "sdk contentful-management.js/5.2.1; platform node.js/v10.15.3; os Windows/10.0.17134;",
"Authorization": "Bearer ...i0Qlc",
"user-agent": "node.js/v10.15.3",
"Accept-Encoding": "gzip",
"X-Contentful-Version": 65,
"Content-Length": 427
},
"method": "put",
"payloadData": "<ENTRY DATA>"
},
"requestId": ""
}
Possible Solution
include a javascript object within the caught error that exposes the X-Contentful-RateLimit-Hour-Limit
, X-Contentful-RateLimit-Hour-Remaining
, X-Contentful-RateLimit-Reset
, X-Contentful-RateLimit-Second-Limit
, X-Contentful-RateLimit-Second-Remaining
headers.
Even better might be to allow me to provide my own Axios client that I could configure myself, which would give me access to the catch
behavior directly.
Steps to Reproduce
- Create a Management Environment client with
retryOnError
set to false
const client = contentfulManagement.createClient({ accessToken: this.config.CONTENT_MANAGEMENT_TOKEN, retryOnError: false });
const space = await client.getSpace(this.spaceId);
const updateEnvironment = await space.getEnvironment(this.environmentId);
- Using this environment client, exceed the rate limit.
while(true) {
try {
await updateEnvironment.getEntry(entryId)
} catch (err) {
console.log(err) // this is where I would like access to rate-limit response headers, but don't have it
}
}
Context
We need to post back to Contentful with an evergreen timestamp in the payload for validation logic which we do on our own. Because we didn't have access to the payload using retryOnError: true
, we needed to roll our own retry logic. Unfortunately, we then encountered this behavior, which prevents us from rate limiting on our side.
Environment
-
Package Version: "contentful": "7.7.0", "contentful-management": "5.8.0",
-
Which API are you using?: Management
Hi @abmagil, You can pass a handler to be called every time you receive a rate limit error and there you will get the headers you need.
const client = contentfulManagement.createClient({ accessToken: this.config.CONTENT_MANAGEMENT_TOKEN, retryOnError: false, logHandler: (loglevel, data)=>{} });
Hi @Khaledgarbaya - I updated my code to be
const logHandler= (loglevel: any, data: any) => {
console.log(loglevel);
console.log(data);
};
// We should delete this hard-coded token and delete it from Contentful.
const client = contentfulManagement.createClient({ accessToken: this.config.CONTENT_MANAGEMENT_TOKEN, retryOnError: false, logHandler});
and re-ran my calls. I saw many Rate limit error occurred. Waiting for 1641 ms before retrying...
errors in my console, but never any logLevel or error data logging. I set a breakpoint in this code and it didn't hit either.
Is there a missing step in your solution? I don't seem to ever hit that code.
Hello. Any update concerning that issue? I do have the same behaviour, using either responseLogger, requestLogger or logHandler.
closing the issue, if you still need help with this please reach out to Contentful support
@n-eit
I have been battling this the last few days.
I found that on a successful response I could access response.headers['x-contentful-ratelimit-reset']
, but in the case of a 429, that is wrapped in an extra layer of response
and so you have to access response.response.headers['x-contentful-ratelimit-reset']
const client = contentful.createClient({
accessToken: '<my-token>',
responseLogger: async (response) => {
if (response.headers) {
console.log(new Date().getTime() / 1000, response.headers['x-contentful-ratelimit-reset'], response.headers['x-contentful-ratelimit-second-limit'], response.headers['x-contentful-ratelimit-second-remaining']);
} else {
console.log(new Date().getTime() / 1000, response.response.headers['x-contentful-ratelimit-reset'], response.response.headers['x-contentful-ratelimit-second-limit'], response.response.headers['x-contentful-ratelimit-second-remaining']);
}
},
});