Skip to content

Commit e4de24f

Browse files
feat(api): Add idempotency key to cards POST and PATCH endpoints
1 parent bb604fb commit e4de24f

File tree

10 files changed

+119
-12
lines changed

10 files changed

+119
-12
lines changed

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 176
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-6e800837b020104545778d65b7b16bae277e6667d98044e83f3bfeacebdb489b.yml
3-
openapi_spec_hash: 94788968e119e8665a1b0d4742565984
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/lithic%2Flithic-eeeb62a4869ba1436c9252f9630006a829695178e86305aea232f6be0d1e3d81.yml
3+
openapi_spec_hash: 25bf9c499cd22240949862e622c534f2
44
config_hash: 2af43c32faa12490c9c9caa2ce62bccb

lithic-java-core/src/main/kotlin/com/lithic/api/models/CardCreateParams.kt

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ import kotlin.jvm.optionals.getOrNull
2727
*/
2828
class CardCreateParams
2929
private constructor(
30+
private val idempotencyKey: String?,
3031
private val body: Body,
3132
private val additionalHeaders: Headers,
3233
private val additionalQueryParams: QueryParams,
3334
) : Params {
3435

36+
fun idempotencyKey(): Optional<String> = Optional.ofNullable(idempotencyKey)
37+
3538
/**
3639
* Card types:
3740
* * `VIRTUAL` - Card will authorize at any merchant and can be added to a digital wallet like
@@ -437,17 +440,25 @@ private constructor(
437440
/** A builder for [CardCreateParams]. */
438441
class Builder internal constructor() {
439442

443+
private var idempotencyKey: String? = null
440444
private var body: Body.Builder = Body.builder()
441445
private var additionalHeaders: Headers.Builder = Headers.builder()
442446
private var additionalQueryParams: QueryParams.Builder = QueryParams.builder()
443447

444448
@JvmSynthetic
445449
internal fun from(cardCreateParams: CardCreateParams) = apply {
450+
idempotencyKey = cardCreateParams.idempotencyKey
446451
body = cardCreateParams.body.toBuilder()
447452
additionalHeaders = cardCreateParams.additionalHeaders.toBuilder()
448453
additionalQueryParams = cardCreateParams.additionalQueryParams.toBuilder()
449454
}
450455

456+
fun idempotencyKey(idempotencyKey: String?) = apply { this.idempotencyKey = idempotencyKey }
457+
458+
/** Alias for calling [Builder.idempotencyKey] with `idempotencyKey.orElse(null)`. */
459+
fun idempotencyKey(idempotencyKey: Optional<String>) =
460+
idempotencyKey(idempotencyKey.getOrNull())
461+
451462
/**
452463
* Sets the entire request body.
453464
*
@@ -974,12 +985,23 @@ private constructor(
974985
* @throws IllegalStateException if any required field is unset.
975986
*/
976987
fun build(): CardCreateParams =
977-
CardCreateParams(body.build(), additionalHeaders.build(), additionalQueryParams.build())
988+
CardCreateParams(
989+
idempotencyKey,
990+
body.build(),
991+
additionalHeaders.build(),
992+
additionalQueryParams.build(),
993+
)
978994
}
979995

980996
fun _body(): Body = body
981997

982-
override fun _headers(): Headers = additionalHeaders
998+
override fun _headers(): Headers =
999+
Headers.builder()
1000+
.apply {
1001+
idempotencyKey?.let { put("Idempotency-Key", it) }
1002+
putAll(additionalHeaders)
1003+
}
1004+
.build()
9831005

9841006
override fun _queryParams(): QueryParams = additionalQueryParams
9851007

@@ -2835,13 +2857,15 @@ private constructor(
28352857
}
28362858

28372859
return other is CardCreateParams &&
2860+
idempotencyKey == other.idempotencyKey &&
28382861
body == other.body &&
28392862
additionalHeaders == other.additionalHeaders &&
28402863
additionalQueryParams == other.additionalQueryParams
28412864
}
28422865

2843-
override fun hashCode(): Int = Objects.hash(body, additionalHeaders, additionalQueryParams)
2866+
override fun hashCode(): Int =
2867+
Objects.hash(idempotencyKey, body, additionalHeaders, additionalQueryParams)
28442868

28452869
override fun toString() =
2846-
"CardCreateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
2870+
"CardCreateParams{idempotencyKey=$idempotencyKey, body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}"
28472871
}

lithic-java-core/src/test/kotlin/com/lithic/api/models/CardCreateParamsTest.kt

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
package com.lithic.api.models
44

5+
import com.lithic.api.core.http.Headers
56
import org.assertj.core.api.Assertions.assertThat
67
import org.junit.jupiter.api.Test
78

@@ -10,6 +11,7 @@ internal class CardCreateParamsTest {
1011
@Test
1112
fun create() {
1213
CardCreateParams.builder()
14+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
1315
.type(CardCreateParams.Type.VIRTUAL)
1416
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
1517
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -47,10 +49,71 @@ internal class CardCreateParamsTest {
4749
.build()
4850
}
4951

52+
@Test
53+
fun headers() {
54+
val params =
55+
CardCreateParams.builder()
56+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
57+
.type(CardCreateParams.Type.VIRTUAL)
58+
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
59+
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
60+
.cardProgramToken("5e9483eb-8103-4e16-9794-2106111b2eca")
61+
.carrier(Carrier.builder().qrCodeUrl("qr_code_url").build())
62+
.digitalCardArtToken("5e9483eb-8103-4e16-9794-2106111b2eca")
63+
.expMonth("06")
64+
.expYear("2027")
65+
.memo("New Card")
66+
.pin("pin")
67+
.productId("1")
68+
.replacementAccountToken("5e9483eb-8103-4e16-9794-2106111b2eca")
69+
.replacementComment("replacement_comment")
70+
.replacementFor("5e9483eb-8103-4e16-9794-2106111b2eca")
71+
.replacementSubstatus(CardCreateParams.ReplacementSubstatus.LOST)
72+
.shippingAddress(
73+
ShippingAddress.builder()
74+
.address1("5 Broad Street")
75+
.city("NEW YORK")
76+
.country("USA")
77+
.firstName("Michael")
78+
.lastName("Bluth")
79+
.postalCode("10001-1809")
80+
.state("NY")
81+
.address2("Unit 25A")
82+
.email("johnny@appleseed.com")
83+
.line2Text("The Bluth Company")
84+
.phoneNumber("+15555555555")
85+
.build()
86+
)
87+
.shippingMethod(CardCreateParams.ShippingMethod._2_DAY)
88+
.spendLimit(1000L)
89+
.spendLimitDuration(SpendLimitDuration.TRANSACTION)
90+
.state(CardCreateParams.State.OPEN)
91+
.build()
92+
93+
val headers = params._headers()
94+
95+
assertThat(headers)
96+
.isEqualTo(
97+
Headers.builder()
98+
.put("Idempotency-Key", "65a9dad4-1b60-4686-83fd-65b25078a4b4")
99+
.build()
100+
)
101+
}
102+
103+
@Test
104+
fun headersWithoutOptionalFields() {
105+
val params = CardCreateParams.builder().type(CardCreateParams.Type.VIRTUAL).build()
106+
107+
val headers = params._headers()
108+
109+
assertThat(headers).isEqualTo(Headers.builder().build())
110+
}
111+
50112
@Test
51113
fun body() {
52114
val params =
53115
CardCreateParams.builder()
116+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
54117
.type(CardCreateParams.Type.VIRTUAL)
55118
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
56119
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")

lithic-java-core/src/test/kotlin/com/lithic/api/models/FinancialAccountCreateParamsTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ internal class FinancialAccountCreateParamsTest {
1111
@Test
1212
fun create() {
1313
FinancialAccountCreateParams.builder()
14-
.idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
14+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
1515
.nickname("nickname")
1616
.type(FinancialAccountCreateParams.Type.OPERATING)
1717
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
@@ -23,7 +23,7 @@ internal class FinancialAccountCreateParamsTest {
2323
fun headers() {
2424
val params =
2525
FinancialAccountCreateParams.builder()
26-
.idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
26+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
2727
.nickname("nickname")
2828
.type(FinancialAccountCreateParams.Type.OPERATING)
2929
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
@@ -35,7 +35,7 @@ internal class FinancialAccountCreateParamsTest {
3535
assertThat(headers)
3636
.isEqualTo(
3737
Headers.builder()
38-
.put("Idempotency-Key", "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
38+
.put("Idempotency-Key", "65a9dad4-1b60-4686-83fd-65b25078a4b4")
3939
.build()
4040
)
4141
}
@@ -57,7 +57,7 @@ internal class FinancialAccountCreateParamsTest {
5757
fun body() {
5858
val params =
5959
FinancialAccountCreateParams.builder()
60-
.idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
60+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
6161
.nickname("nickname")
6262
.type(FinancialAccountCreateParams.Type.OPERATING)
6363
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")

lithic-java-core/src/test/kotlin/com/lithic/api/services/ErrorHandlingTest.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ internal class ErrorHandlingTest {
7575
assertThrows<BadRequestException> {
7676
cardService.create(
7777
CardCreateParams.builder()
78+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
7879
.type(CardCreateParams.Type.VIRTUAL)
7980
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
8081
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -132,6 +133,7 @@ internal class ErrorHandlingTest {
132133
assertThrows<BadRequestException> {
133134
cardService.create(
134135
CardCreateParams.builder()
136+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
135137
.type(CardCreateParams.Type.VIRTUAL)
136138
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
137139
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -189,6 +191,7 @@ internal class ErrorHandlingTest {
189191
assertThrows<UnauthorizedException> {
190192
cardService.create(
191193
CardCreateParams.builder()
194+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
192195
.type(CardCreateParams.Type.VIRTUAL)
193196
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
194197
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -246,6 +249,7 @@ internal class ErrorHandlingTest {
246249
assertThrows<UnauthorizedException> {
247250
cardService.create(
248251
CardCreateParams.builder()
252+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
249253
.type(CardCreateParams.Type.VIRTUAL)
250254
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
251255
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -303,6 +307,7 @@ internal class ErrorHandlingTest {
303307
assertThrows<PermissionDeniedException> {
304308
cardService.create(
305309
CardCreateParams.builder()
310+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
306311
.type(CardCreateParams.Type.VIRTUAL)
307312
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
308313
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -360,6 +365,7 @@ internal class ErrorHandlingTest {
360365
assertThrows<PermissionDeniedException> {
361366
cardService.create(
362367
CardCreateParams.builder()
368+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
363369
.type(CardCreateParams.Type.VIRTUAL)
364370
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
365371
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -417,6 +423,7 @@ internal class ErrorHandlingTest {
417423
assertThrows<NotFoundException> {
418424
cardService.create(
419425
CardCreateParams.builder()
426+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
420427
.type(CardCreateParams.Type.VIRTUAL)
421428
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
422429
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -474,6 +481,7 @@ internal class ErrorHandlingTest {
474481
assertThrows<NotFoundException> {
475482
cardService.create(
476483
CardCreateParams.builder()
484+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
477485
.type(CardCreateParams.Type.VIRTUAL)
478486
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
479487
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -531,6 +539,7 @@ internal class ErrorHandlingTest {
531539
assertThrows<UnprocessableEntityException> {
532540
cardService.create(
533541
CardCreateParams.builder()
542+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
534543
.type(CardCreateParams.Type.VIRTUAL)
535544
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
536545
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -588,6 +597,7 @@ internal class ErrorHandlingTest {
588597
assertThrows<UnprocessableEntityException> {
589598
cardService.create(
590599
CardCreateParams.builder()
600+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
591601
.type(CardCreateParams.Type.VIRTUAL)
592602
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
593603
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -645,6 +655,7 @@ internal class ErrorHandlingTest {
645655
assertThrows<RateLimitException> {
646656
cardService.create(
647657
CardCreateParams.builder()
658+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
648659
.type(CardCreateParams.Type.VIRTUAL)
649660
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
650661
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -702,6 +713,7 @@ internal class ErrorHandlingTest {
702713
assertThrows<RateLimitException> {
703714
cardService.create(
704715
CardCreateParams.builder()
716+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
705717
.type(CardCreateParams.Type.VIRTUAL)
706718
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
707719
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -759,6 +771,7 @@ internal class ErrorHandlingTest {
759771
assertThrows<InternalServerException> {
760772
cardService.create(
761773
CardCreateParams.builder()
774+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
762775
.type(CardCreateParams.Type.VIRTUAL)
763776
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
764777
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -816,6 +829,7 @@ internal class ErrorHandlingTest {
816829
assertThrows<InternalServerException> {
817830
cardService.create(
818831
CardCreateParams.builder()
832+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
819833
.type(CardCreateParams.Type.VIRTUAL)
820834
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
821835
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -873,6 +887,7 @@ internal class ErrorHandlingTest {
873887
assertThrows<UnexpectedStatusCodeException> {
874888
cardService.create(
875889
CardCreateParams.builder()
890+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
876891
.type(CardCreateParams.Type.VIRTUAL)
877892
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
878893
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -930,6 +945,7 @@ internal class ErrorHandlingTest {
930945
assertThrows<UnexpectedStatusCodeException> {
931946
cardService.create(
932947
CardCreateParams.builder()
948+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
933949
.type(CardCreateParams.Type.VIRTUAL)
934950
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
935951
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")
@@ -985,6 +1001,7 @@ internal class ErrorHandlingTest {
9851001
assertThrows<LithicException> {
9861002
cardService.create(
9871003
CardCreateParams.builder()
1004+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
9881005
.type(CardCreateParams.Type.VIRTUAL)
9891006
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
9901007
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")

lithic-java-core/src/test/kotlin/com/lithic/api/services/ServiceParamsTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ internal class ServiceParamsTest {
4545

4646
cardService.create(
4747
CardCreateParams.builder()
48+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
4849
.type(CardCreateParams.Type.VIRTUAL)
4950
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
5051
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")

lithic-java-core/src/test/kotlin/com/lithic/api/services/async/CardServiceAsyncTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ internal class CardServiceAsyncTest {
3434
val cardFuture =
3535
cardServiceAsync.create(
3636
CardCreateParams.builder()
37+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
3738
.type(CardCreateParams.Type.VIRTUAL)
3839
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
3940
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")

lithic-java-core/src/test/kotlin/com/lithic/api/services/async/FinancialAccountServiceAsyncTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal class FinancialAccountServiceAsyncTest {
2626
val financialAccountFuture =
2727
financialAccountServiceAsync.create(
2828
FinancialAccountCreateParams.builder()
29-
.idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
29+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
3030
.nickname("nickname")
3131
.type(FinancialAccountCreateParams.Type.OPERATING)
3232
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")

lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/CardServiceTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ internal class CardServiceTest {
3434
val card =
3535
cardService.create(
3636
CardCreateParams.builder()
37+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
3738
.type(CardCreateParams.Type.VIRTUAL)
3839
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
3940
.bulkOrderToken("5e9483eb-8103-4e16-9794-2106111b2eca")

lithic-java-core/src/test/kotlin/com/lithic/api/services/blocking/FinancialAccountServiceTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal class FinancialAccountServiceTest {
2626
val financialAccount =
2727
financialAccountService.create(
2828
FinancialAccountCreateParams.builder()
29-
.idempotencyKey("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
29+
.idempotencyKey("65a9dad4-1b60-4686-83fd-65b25078a4b4")
3030
.nickname("nickname")
3131
.type(FinancialAccountCreateParams.Type.OPERATING)
3232
.accountToken("182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")

0 commit comments

Comments
 (0)