stripe / stripe-java

Java library for the Stripe API.

Home Page:https://stripe.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Way to intercept an answer from the API

maxime1992 opened this issue · comments

commented

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