From 3285df2deb59c88b9904351ac75667555f8a74e2 Mon Sep 17 00:00:00 2001 From: Thiago Cardoso Date: Wed, 17 Jul 2024 14:28:35 -0300 Subject: [PATCH] feat: add/use RFC3339 fields in requests Timestamp fields that store time as milliseconds since epoch are being replaced by fields that store it as a RFC 3339 string. This commit: - Removes POST /feedbacks `timestamp` field, replacing it with `occurred_at`. Removal is possible because this field is not in the public API. - Add `collected_at` to POST /signups' `additional_locations`. This field should be used instead of the existing `timestamp`. --- build.gradle | 1 + .../java/com/incognia/api/IncogniaAPI.java | 63 +++++++++++++------ .../api/clients/ObjectMapperFactory.java | 6 +- .../incognia/common/AdditionalLocation.java | 4 +- .../feedback/PostFeedbackRequestBody.java | 4 +- .../com/incognia/api/IncogniaAPITest.java | 2 +- 6 files changed, 58 insertions(+), 22 deletions(-) diff --git a/build.gradle b/build.gradle index c7f849e..c1d6ac4 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,7 @@ dependencies { implementation platform("com.squareup.okhttp3:okhttp-bom:4.12.0") implementation "com.squareup.okhttp3:okhttp" implementation "com.fasterxml.jackson.core:jackson-databind:2.17.1" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1" testImplementation 'com.auth0:java-jwt:4.4.0' testImplementation 'commons-io:commons-io:2.16.1' diff --git a/src/main/java/com/incognia/api/IncogniaAPI.java b/src/main/java/com/incognia/api/IncogniaAPI.java index 338590d..fac2057 100644 --- a/src/main/java/com/incognia/api/IncogniaAPI.java +++ b/src/main/java/com/incognia/api/IncogniaAPI.java @@ -68,7 +68,7 @@ public IncogniaAPI(String clientId, String clientSecret) { * Example: * *
{@code
-   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret", Region.BR);
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
    * try {
    *      Address address = Address address =
    *         Address.builder()
@@ -128,7 +128,7 @@ public SignupAssessment registerSignup(RegisterSignupRequest request) throws Inc
    * Example:
    *
    * 
{@code
-   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret", Region.BR);
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
    * try {
    *     RegisterLoginRequest loginRequest = RegisterLoginRequest.builder()
    *         .installationId("installation-id")
@@ -183,7 +183,7 @@ public TransactionAssessment registerLogin(RegisterLoginRequest request)
    * Example:
    *
    * 
{@code
-   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret", Region.BR);
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
    * try {
    *     RegisterLoginRequest loginRequest = RegisterLoginRequest.builder()
    *         .accountId("account-id")
@@ -237,7 +237,7 @@ public TransactionAssessment registerWebLogin(RegisterWebLoginRequest request)
    * Example:
    *
    * 
{@code
-   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret", Region.BR);
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
    * try {
    *      RegisterWebSignupRequest webSignupRequest = RegisterWebSignupRequest.builder().sessionToken(sessionToken).address(address).build();
    *      SignupAssessment assessment = api.registerSignup(webSignupRequest);
@@ -275,7 +275,7 @@ public SignupAssessment registerWebSignup(RegisterWebSignupRequest request)
    * Example:
    *
    * 
{@code
-   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret", Region.BR);
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
    * try {
    *      Address address = Address address =
    *         Address.builder()
@@ -374,19 +374,16 @@ public TransactionAssessment registerPayment(RegisterPaymentRequest request)
    * Example:
    *
    * 
{@code
-   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret", Region.BR);
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
    * try {
-   *      Instant timestamp = Instant.now();
-   *      client.registerFeedback(
+   *     Instant occurredAt = Instant.parse("2024-07-22T15:20:00Z");
+   *     api.registerFeedback(
    *         FeedbackEvent.ACCOUNT_TAKEOVER,
-   *         timestamp,
+   *         occurredAt,
    *         FeedbackIdentifiers.builder()
    *             .installationId("installation-id")
-   *             .sessionToken("session-token")
    *             .accountId("account-id")
-   *             .externalId("external-id")
-   *             .signupId("c9ac2803-c868-4b7a-8323-8a6b96298ebe")
-   *             .build();
+   *             .build());
    * } catch (IncogniaAPIException e) {
    *      //Some api error happened (invalid data, invalid credentials)
    * } catch (IncogniaException e) {
@@ -395,27 +392,57 @@ public TransactionAssessment registerPayment(RegisterPaymentRequest request)
    * }
* * @param feedbackEvent type of feedback event - * @param timestamp Instant when the fraud or event happened + * @param occurredAt Instant when the fraud or event happened * @param identifiers the user's identifiers * @throws IncogniaAPIException in case of api errors * @throws IncogniaException in case of unexpected errors */ public void registerFeedback( - FeedbackEvent feedbackEvent, Instant timestamp, FeedbackIdentifiers identifiers) + FeedbackEvent feedbackEvent, Instant occurredAt, FeedbackIdentifiers identifiers) throws IncogniaException { - registerFeedback(feedbackEvent, timestamp, identifiers, false); + registerFeedback(feedbackEvent, occurredAt, identifiers, false); } + /** + * Shares feedback about a risk decision, improving the quality of risk assessments. Check the docs
+ * Example: + * + *
{@code
+   * IncogniaAPI api = new IncogniaAPI("client-id", "client-secret");
+   * try {
+   *     Instant occurredAt = Instant.parse("2024-07-22T15:20:00Z");
+   *     api.registerFeedback(
+   *         FeedbackEvent.ACCOUNT_TAKEOVER,
+   *         occurredAt,
+   *         FeedbackIdentifiers.builder()
+   *             .installationId("installation-id")
+   *             .accountId("account-id")
+   *             .build());
+   * } catch (IncogniaAPIException e) {
+   *      //Some api error happened (invalid data, invalid credentials)
+   * } catch (IncogniaException e) {
+   *      //Something unexpected happened
+   * }
+   * }
+ * + * @param feedbackEvent type of feedback event + * @param occurredAt Instant when the fraud or event happened + * @param identifiers the user's identifiers + * @param dryRun whether this request is a dry-run + * @throws IncogniaAPIException in case of api errors + * @throws IncogniaException in case of unexpected errors + */ public void registerFeedback( FeedbackEvent feedbackEvent, - Instant timestamp, + Instant occurredAt, FeedbackIdentifiers identifiers, boolean dryRun) throws IncogniaException { PostFeedbackRequestBody requestBody = PostFeedbackRequestBody.builder() .event(feedbackEvent) - .timestamp(timestamp.toEpochMilli()) + .occurredAt(occurredAt) .installationId(identifiers.getInstallationId()) .sessionToken(identifiers.getSessionToken()) .accountId(identifiers.getAccountId()) diff --git a/src/main/java/com/incognia/api/clients/ObjectMapperFactory.java b/src/main/java/com/incognia/api/clients/ObjectMapperFactory.java index 472d72f..61569a7 100644 --- a/src/main/java/com/incognia/api/clients/ObjectMapperFactory.java +++ b/src/main/java/com/incognia/api/clients/ObjectMapperFactory.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; public class ObjectMapperFactory { @SuppressWarnings("deprecation") @@ -11,7 +13,9 @@ public class ObjectMapperFactory { // jackson versions public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() + .registerModule(new JavaTimeModule()) .setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE) .setSerializationInclusion(Include.NON_NULL) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); } diff --git a/src/main/java/com/incognia/common/AdditionalLocation.java b/src/main/java/com/incognia/common/AdditionalLocation.java index 0163dd2..83fe175 100644 --- a/src/main/java/com/incognia/common/AdditionalLocation.java +++ b/src/main/java/com/incognia/common/AdditionalLocation.java @@ -1,5 +1,6 @@ package com.incognia.common; +import java.time.Instant; import lombok.Builder; import lombok.Value; @@ -8,5 +9,6 @@ public class AdditionalLocation { Double lat; Double lng; - Long timestamp; + @Deprecated Long timestamp; + Instant collectedAt; } diff --git a/src/main/java/com/incognia/feedback/PostFeedbackRequestBody.java b/src/main/java/com/incognia/feedback/PostFeedbackRequestBody.java index e8299d5..763df6e 100644 --- a/src/main/java/com/incognia/feedback/PostFeedbackRequestBody.java +++ b/src/main/java/com/incognia/feedback/PostFeedbackRequestBody.java @@ -1,5 +1,6 @@ package com.incognia.feedback; +import java.time.Instant; import lombok.Builder; import lombok.Value; @@ -7,7 +8,8 @@ @Builder public class PostFeedbackRequestBody { FeedbackEvent event; - Long timestamp; + @Deprecated Long timestamp; + Instant occurredAt; String accountId; String externalId; String installationId; diff --git a/src/test/java/com/incognia/api/IncogniaAPITest.java b/src/test/java/com/incognia/api/IncogniaAPITest.java index a398186..ea3c0d8 100644 --- a/src/test/java/com/incognia/api/IncogniaAPITest.java +++ b/src/test/java/com/incognia/api/IncogniaAPITest.java @@ -556,7 +556,7 @@ void testRegisterFeedback_whenDataIsValid(boolean dryRun) { .signupId(signupId) .accountId(accountId) .event(FeedbackEvent.ACCOUNT_TAKEOVER) - .timestamp(timestamp.toEpochMilli()) + .occurredAt(timestamp) .build()); mockServer.setDispatcher(dispatcher); client.registerFeedback(