Way to intercept an answer from the API
maxime1992 opened this issue · comments
Is your feature request related to a problem? Please describe.
If anything goes wrong and we need to get in touch with Stripe team about an HTTP call, we'll be asked to provide the request ID.
I would like to have a way to log every request happening with the request ID.
Looking at the Java implementation, there doesn't seem to be a way to hook into the static request
method.
Describe the solution you'd like
Stripe API could provide a method to register interceptors that'd be called when there's an answer.
Describe alternatives you've considered
(Working in Kotlin).
-
Use
also
on every request and manually log from there. Quite error prone and can even be completely forgotten -
I could create an inline function for facilitating the logging and avoid repeating too much but it can still be forgotten and would have to be implemented for each type (
Customer
, etc):
inline fun Customer.logWithRequestId(): Customer {
LoggerFactory
.getLogger(this::class.java)
.info("Created customer ${it.id} (request ID \" ${it.lastResponse.requestId()}\"")
return this
}
It's also not that good because we don't know here if the Customer
object in question was created, updated, removed etc. So we'd have to pass a string or an enum to logWithRequestId
and it could be easily forgotten while copy/pasting for example, ending up with the wrong logging... So far from ideal of course.
So none of this is ideal really.
Additional context
No response
Hi @maxime1992 , apologies for the delay in this response and thank you for opening this issue! We would like to add request logging to stripe-java in the future - I'll keep this issue open to track the feature request.
However, in the meantime you can achieve a similar effect by subclassing the StripeResponseGetter
interface and logging the information you want, which in this example is the request ID:
Stripe.api_key = "sk_..."
val myStripeResponseGetter = object: LiveStripeResponseGetter() {
@Throws(StripeException::class)
override fun <T : StripeObjectInterface?> request(
method: RequestMethod?,
url: String?,
params: Map<String?, Any?>?,
clazz: Class<T>?,
options: RequestOptions?
): T? {
try {
var stripeObject: T = super.request(method, url, params, clazz, options)
println(stripeObject?.getLastResponse()?.requestId());
return stripeObject;
} catch (e: StripeException) {
println(e.requestId)
throw e;
}
}
}
ApiResource.setStripeResponseGetter(myStripeResponseGetter)
// send requests
Disclaimer: This is my first time writing Kotlin, and it is very possible that what I have provided is not idiomatic. However, it seems to work from my testing. 😅
Wrapping the LiveStripeResponseGetter
is the recommended way to intercept all requests/responses in one place.
A more complete example:
@Bean
StripeResponseGetter stripeResponseGetter() {
final String apiKey = System.getenv().get("STRIPE_API_KEY");
Stripe.apiKey = apiKey;
Stripe.setMaxNetworkRetries(3);
final var stripeResponseGetter = new LiveStripeResponseGetter() {
@Override
public <T extends StripeObjectInterface> T request(ApiRequest apiRequest, Type typeToken)
throws StripeException {
final var startTime = System.currentTimeMillis();
log.info("[StripeClient]: Method: {}. Path: {}. Params: {}", apiRequest.getMethod(),
apiRequest.getPath(),
apiRequest.getParams());
try {
final T response = super.request(apiRequest, typeToken);
log.info("[StripeClient]: Method: {}. Path: {}. {}", apiRequest.getMethod(), apiRequest.getPath(),
response.getLastResponse());
return response;
} catch (StripeException e) {
log.error("[StripeClient]: Method: {}. Path: {}. Error: {}", apiRequest.getMethod(),
apiRequest.getPath(), e);
throw e;
} finally {
log.info("[StripeClient]: Method: {}. Path: {} Duration: {}ms", apiRequest.getMethod(),
apiRequest.getPath(),
System.currentTimeMillis() - startTime);
}
}
};
ApiResource.setStripeResponseGetter(stripeResponseGetter);
return stripeResponseGetter;
}
@Bean
StripeClient providesClient(StripeResponseGetter stripeResponseGetter) {
return new StripeClient(stripeResponseGetter);
}
Note: I am using spring