• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stripe / stripe-java / #16493

03 Oct 2024 07:15PM UTC coverage: 12.942% (+0.08%) from 12.864%
#16493

push

github

web-flow
Merge Stripe-java v27.0.0 to beta branch (#1888)

409 of 1651 new or added lines in 88 files covered. (24.77%)

31 existing lines in 7 files now uncovered.

18773 of 145050 relevant lines covered (12.94%)

0.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.67
/src/main/java/com/stripe/net/StripeRequest.java
1
package com.stripe.net;
2

3
import com.stripe.Stripe;
4
import com.stripe.exception.ApiConnectionException;
5
import com.stripe.exception.AuthenticationException;
6
import com.stripe.exception.StripeException;
7
import java.io.IOException;
8
import java.net.URL;
9
import java.util.*;
10
import lombok.AccessLevel;
11
import lombok.AllArgsConstructor;
12
import lombok.Value;
13
import lombok.experimental.Accessors;
14

15
/** A request to Stripe's API. */
16
@Value
17
@AllArgsConstructor(access = AccessLevel.PROTECTED)
18
@Accessors(fluent = true)
19
public class StripeRequest {
20
  /** The HTTP method for the request (GET, POST or DELETE). */
21
  ApiResource.RequestMethod method;
22

23
  /**
24
   * The URL for the request. If this is a GET or DELETE request, the URL also includes the request
25
   * parameters in its query string.
26
   */
27
  URL url;
28

29
  /**
30
   * The body of the request. For POST requests, this will be either a {@code
31
   * application/x-www-form-urlencoded} or a {@code multipart/form-data} payload. For non-POST
32
   * requests, this will be {@code null}.
33
   */
34
  HttpContent content;
35

36
  /**
37
   * The HTTP headers of the request ({@code Authorization}, {@code Stripe-Version}, {@code
38
   * Stripe-Account}, {@code Idempotency-Key}...).
39
   */
40
  HttpHeaders headers;
41

42
  /** The parameters of the request (as an unmodifiable map). */
43
  Map<String, Object> params;
44

45
  /** The special modifiers of the request. */
46
  RequestOptions options;
47

48
  /**
49
   * Initializes a new instance of the {@link StripeRequest} class.
50
   *
51
   * @param method the HTTP method
52
   * @param url the URL of the request
53
   * @param content the body of the request
54
   * @param params the parameters of the request
55
   * @param options the special modifiers of the request
56
   * @throws StripeException if the request cannot be initialized for any reason
57
   */
58
  private StripeRequest(
59
      ApiResource.RequestMethod method,
60
      String url,
61
      HttpContent content,
62
      Map<String, Object> params,
63
      RequestOptions options,
64
      ApiMode apiMode)
65
      throws StripeException {
1✔
66
    try {
67
      this.content = content;
1✔
68
      this.params = (params != null) ? Collections.unmodifiableMap(params) : null;
1✔
69
      this.options = (options != null) ? options : RequestOptions.getDefault();
1✔
70
      this.method = method;
1✔
71
      this.url = buildURL(method, url, params, apiMode);
1✔
72
      this.headers = buildHeaders(method, this.options, this.content, apiMode);
1✔
NEW
73
    } catch (IOException e) {
×
NEW
74
      throw new ApiConnectionException(
×
NEW
75
          String.format(
×
76
              "IOException during API request to Stripe (%s): %s "
77
                  + "Please check your internet connection and try again. If this problem persists,"
78
                  + "you should check Stripe's service status at https://twitter.com/stripestatus,"
79
                  + " or let us know at support@stripe.com.",
NEW
80
              Stripe.getApiBase(), e.getMessage()),
×
81
          e);
82
    }
1✔
83
  }
1✔
84

85
  /**
86
   * Initializes a new instance of the {@link StripeRequest} class.
87
   *
88
   * @param method the HTTP method
89
   * @param url the URL of the request
90
   * @param params the parameters of the request
91
   * @param options the special modifiers of the request
92
   * @param apiMode version of the API
93
   * @throws StripeException if the request cannot be initialized for any reason
94
   */
95
  StripeRequest(
96
      ApiResource.RequestMethod method,
97
      String url,
98
      Map<String, Object> params,
99
      RequestOptions options,
100
      ApiMode apiMode)
101
      throws StripeException {
1✔
102
    try {
103
      this.params = (params != null) ? Collections.unmodifiableMap(params) : null;
1✔
104
      this.options = options;
1✔
105
      this.method = method;
1✔
106
      this.url = buildURL(method, url, params, apiMode);
1✔
107
      this.content = buildContent(method, params, apiMode);
1✔
108
      this.headers = buildHeaders(method, this.options, this.content, apiMode);
1✔
NEW
109
    } catch (IOException e) {
×
NEW
110
      throw new ApiConnectionException(
×
NEW
111
          String.format(
×
112
              "IOException during API request to Stripe (%s): %s "
113
                  + "Please check your internet connection and try again. If this problem persists,"
114
                  + "you should check Stripe's service status at https://twitter.com/stripestatus,"
115
                  + " or let us know at support@stripe.com.",
NEW
116
              Stripe.getApiBase(), e.getMessage()),
×
117
          e);
118
    }
1✔
119
  }
1✔
120

121
  /**
122
   * Initializes a new instance of the {@link StripeRequest} class.
123
   *
124
   * @param method the HTTP method
125
   * @param url the URL of the request
126
   * @param params the parameters of the request
127
   * @param options the special modifiers of the request
128
   * @throws StripeException if the request cannot be initialized for any reason
129
   */
130
  public static StripeRequest create(
131
      ApiResource.RequestMethod method,
132
      String url,
133
      Map<String, Object> params,
134
      RequestOptions options,
135
      ApiMode apiMode)
136
      throws StripeException {
137
    if (options == null) {
1✔
NEW
138
      throw new IllegalArgumentException("options parameter should not be null");
×
139
    }
140

141
    StripeRequest request = new StripeRequest(method, url, params, options, apiMode);
1✔
142
    Authenticator authenticator = options.getAuthenticator();
1✔
143

144
    if (authenticator == null) {
1✔
145
      throw new AuthenticationException(
1✔
146
          "No API key provided. Set your API key using `Stripe.apiKey = \"<API-KEY>\"`. You can "
147
              + "generate API keys from the Stripe Dashboard. See "
148
              + "https://stripe.com/docs/api/authentication for details or contact support at "
149
              + "https://support.stripe.com/email if you have any questions.",
150
          null,
151
          null,
152
          0);
1✔
153
    }
154

155
    request = request.options().getAuthenticator().authenticate(request);
1✔
156

157
    return request;
1✔
158
  }
159

160
  /**
161
   * Initializes a new instance of the {@link StripeRequest} class.
162
   *
163
   * @param method the HTTP method
164
   * @param url the URL of the request
165
   * @param content the body of the request
166
   * @param options the special modifiers of the request
167
   * @throws StripeException if the request cannot be initialized for any reason
168
   */
169
  public static StripeRequest createWithStringContent(
170
      ApiResource.RequestMethod method,
171
      String url,
172
      String content,
173
      RequestOptions options,
174
      ApiMode apiMode)
175
      throws StripeException {
176
    StripeRequest request =
1✔
177
        new StripeRequest(
178
            method, url, buildContentFromString(method, content, apiMode), null, options, apiMode);
1✔
179

180
    Authenticator authenticator = options.getAuthenticator();
1✔
181

182
    if (authenticator == null) {
1✔
NEW
183
      throw new AuthenticationException(
×
184
          "No API key provided. Set your API key using `Stripe.apiKey = \"<API-KEY>\"`. You can "
185
              + "generate API keys from the Stripe Dashboard. See "
186
              + "https://stripe.com/docs/api/authentication for details or contact support at "
187
              + "https://support.stripe.com/email if you have any questions.",
188
          null,
189
          null,
NEW
190
          0);
×
191
    }
192

193
    request = request.options().getAuthenticator().authenticate(request);
1✔
194

195
    return request;
1✔
196
  }
197

198
  /**
199
   * Returns a new {@link StripeRequest} instance with an additional header.
200
   *
201
   * @param name the additional header's name
202
   * @param value the additional header's value
203
   * @return the new {@link StripeRequest} instance
204
   */
205
  public StripeRequest withAdditionalHeader(String name, String value) {
206
    return new StripeRequest(
1✔
207
        this.method,
208
        this.url,
209
        this.content,
210
        this.headers.withAdditionalHeader(name, value),
1✔
211
        this.params,
212
        this.options);
213
  }
214

215
  private static URL buildURL(
216
      ApiResource.RequestMethod method, String spec, Map<String, Object> params, ApiMode apiMode)
217
      throws IOException {
218
    StringBuilder sb = new StringBuilder();
1✔
219

220
    sb.append(spec);
1✔
221

222
    URL specUrl = new URL(spec);
1✔
223
    String specQueryString = specUrl.getQuery();
1✔
224

225
    if ((method != ApiResource.RequestMethod.POST) && (params != null)) {
1✔
226
      String queryString =
1✔
227
          FormEncoder.createQueryString(params, apiMode == ApiMode.V2 ? true : false);
1✔
228

229
      if (queryString != null && !queryString.isEmpty()) {
1✔
230
        if (specQueryString != null && !specQueryString.isEmpty()) {
1✔
231
          sb.append("&");
1✔
232
        } else {
233
          sb.append("?");
1✔
234
        }
235
        sb.append(queryString);
1✔
236
      }
237
    }
238

239
    return new URL(sb.toString());
1✔
240
  }
241

242
  private static HttpContent buildContent(
243
      ApiResource.RequestMethod method, Map<String, Object> params, ApiMode apiMode)
244
      throws IOException {
245
    if (method != ApiResource.RequestMethod.POST) {
1✔
246
      return null;
1✔
247
    }
248

249
    if (apiMode == ApiMode.V2) {
1✔
250
      return JsonEncoder.createHttpContent(params);
1✔
251
    }
252

253
    return FormEncoder.createHttpContent(params);
1✔
254
  }
255

256
  private static HttpContent buildContentFromString(
257
      ApiResource.RequestMethod method, String content, ApiMode apiMode)
258
      throws ApiConnectionException {
259
    if (method != ApiResource.RequestMethod.POST) {
1✔
260
      return null;
1✔
261
    }
262

263
    if (apiMode == ApiMode.V2) {
1✔
264
      return HttpContent.buildJsonContent(content);
1✔
265
    }
266

267
    HttpContent httpContent = null;
1✔
268
    try {
269
      httpContent = HttpContent.buildFormURLEncodedContent(content);
1✔
270
    } catch (IOException e) {
×
271
      handleIOException(e);
×
272
    }
1✔
273
    return httpContent;
1✔
274
  }
275

276
  private static void handleIOException(IOException e) throws ApiConnectionException {
277
    throw new ApiConnectionException(
×
278
        String.format(
×
279
            "IOException during API request to Stripe (%s): %s "
280
                + "Please check your internet connection and try again. If this problem persists,"
281
                + "you should check Stripe's service status at https://twitter.com/stripestatus,"
282
                + " or let us know at support@stripe.com.",
283
            Stripe.getApiBase(), e.getMessage()),
×
284
        e);
285
  }
286

287
  private static HttpHeaders buildHeaders(
288
      ApiResource.RequestMethod method,
289
      RequestOptions options,
290
      HttpContent content,
291
      ApiMode apiMode) {
292
    Map<String, List<String>> headerMap = new HashMap<String, List<String>>();
1✔
293

294
    // Accept
295
    headerMap.put("Accept", Arrays.asList("application/json"));
1✔
296

297
    // Accept-Charset
298
    headerMap.put("Accept-Charset", Arrays.asList(ApiResource.CHARSET.name()));
1✔
299

300
    // Stripe-Version
301
    if (RequestOptions.unsafeGetStripeVersionOverride(options) != null) {
1✔
302
      headerMap.put(
1✔
303
          "Stripe-Version", Arrays.asList(RequestOptions.unsafeGetStripeVersionOverride(options)));
1✔
304
    } else if (options.getStripeVersion() != null) {
1✔
305
      headerMap.put("Stripe-Version", Arrays.asList(options.getStripeVersion()));
1✔
306
    }
307

308
    if (apiMode == ApiMode.V1) {
1✔
309
      if (options.getStripeContext() != null) {
1✔
310
        throw new UnsupportedOperationException("Context is not supported in V1 APIs");
1✔
311
      }
312
    } else {
313
      if (options.getStripeContext() != null) {
1✔
314
        headerMap.put("Stripe-Context", Arrays.asList(options.getStripeContext()));
1✔
315
      }
316
      if (content != null) {
1✔
317
        headerMap.put("Content-Type", Arrays.asList(content.contentType()));
1✔
318
      }
319
    }
320

321
    // Stripe-Account
322
    if (options.getStripeAccount() != null) {
1✔
323
      headerMap.put("Stripe-Account", Arrays.asList(options.getStripeAccount()));
1✔
324
    }
325

326
    // Idempotency-Key
327
    if (options.getIdempotencyKey() != null) {
1✔
328
      headerMap.put("Idempotency-Key", Arrays.asList(options.getIdempotencyKey()));
1✔
329
    } else if (method == ApiResource.RequestMethod.POST
1✔
330
        || (apiMode == ApiMode.V2 && method == ApiResource.RequestMethod.DELETE)) {
331
      headerMap.put("Idempotency-Key", Arrays.asList(UUID.randomUUID().toString()));
1✔
332
    }
333

334
    return HttpHeaders.of(headerMap);
1✔
335
  }
336
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc