-
-
Notifications
You must be signed in to change notification settings - Fork 45
Created Retrofit, Api handlers, callbacks for connect API calling #3213
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Created Retrofit, Api handlers, callbacks for connect API calling #3213
Conversation
📝 WalkthroughWalkthroughThis change introduces a major refactor and modularization of the API client and handler architecture for Personal ID and Connect network interactions. The legacy Sequence Diagram(s)sequenceDiagram
participant User
participant PersonalIdCredentialActivity
participant ConnectApiHandler
participant ApiPersonalId
participant ConnectApiClient
participant ApiService
User->>PersonalIdCredentialActivity: Launch Activity
PersonalIdCredentialActivity->>ConnectApiHandler: retrieveCredentials()
ConnectApiHandler->>ApiPersonalId: retrieveCredentials(context, username, password, callback)
ApiPersonalId->>ConnectApiClient: getClientApi()
ConnectApiClient->>ApiService: retrieveCredentials(Authorization)
ApiService-->>ConnectApiClient: Response (credentials or error)
ConnectApiClient-->>ApiPersonalId: Response
ApiPersonalId-->>ConnectApiHandler: Callback (onSuccess/onFailure)
ConnectApiHandler-->>PersonalIdCredentialActivity: onSuccess/onFailure
Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches
🧪 Generate Unit Tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (7)
app/src/org/commcare/connect/network/base/BaseApiClient.kt (2)
28-34: Consider more robust API version handling.The current implementation only adds the Accept header when
apiVersionis not empty, but it doesn't validate the version format. Consider adding validation or using a more structured approach for API versioning.- if (!TextUtils.isEmpty(apiVersion)) { - requestWithHeadersBuilder.header( - "Accept", - "application/json;version=" + apiVersion - ) - } + if (!TextUtils.isEmpty(apiVersion)) { + // Consider validating apiVersion format here + requestWithHeadersBuilder.header( + "Accept", + "application/json;version=$apiVersion" + ) + }
36-39: Consider making timeout values configurable.The 30-second timeout values are reasonable defaults, but consider making them configurable for different API endpoints that might need different timeout characteristics.
app/src/org/commcare/connect/network/connectId/parser/CompleteProfileResponseParser.java (1)
23-26: Consider more descriptive error handling for required fields.While
Objects.requireNonNullensures these fields are present, it throws a genericNullPointerExceptionif any field is missing. Consider providing more descriptive error messages or custom exceptions to aid in debugging.- sessionData.setPersonalId(Objects.requireNonNull(JsonExtensions.optStringSafe(json, "username", null))); - sessionData.setDbKey(Objects.requireNonNull(JsonExtensions.optStringSafe(json, "db_key", null))); - sessionData.setOauthPassword(Objects.requireNonNull(JsonExtensions.optStringSafe(json, "password", null))); + sessionData.setPersonalId(Objects.requireNonNull(JsonExtensions.optStringSafe(json, "username", null), "username is required")); + sessionData.setDbKey(Objects.requireNonNull(JsonExtensions.optStringSafe(json, "db_key", null), "db_key is required")); + sessionData.setOauthPassword(Objects.requireNonNull(JsonExtensions.optStringSafe(json, "password", null), "password is required"));app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt (1)
7-7: Remove the empty default constructor.The empty default constructor is unnecessary and can be removed to clean up the code.
-class NoParsingResponseParser<T>() : ConnectApiResponseParser<T> { +class NoParsingResponseParser<T> : ConnectApiResponseParser<T> {app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt (1)
10-10: Remove the empty default constructor.The empty default constructor is unnecessary and can be removed to clean up the code.
-class RetrieveCredentialsResponseParser<T>() : ConnectApiResponseParser<T> { +class RetrieveCredentialsResponseParser<T> : ConnectApiResponseParser<T> {app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt (1)
24-37: Consider adding TODO comments for empty callback methods.The empty
onSuccessandonFailuremethods appear to be placeholders. Consider adding TODO comments to indicate the intended future implementation.object : ConnectApiHandler<PersonalIdValidAndCorruptCredential>() { override fun onSuccess(personalIdValidAndCorruptCredential: PersonalIdValidAndCorruptCredential) { + // TODO: Handle successful credential retrieval } override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) { + // TODO: Handle credential retrieval failure } }.retrieveCredentials(this, user.name, user.password)app/src/org/commcare/connect/network/connect/ConnectApiClient.kt (1)
17-26: Singleton implementation is thread-safe and efficient.The double-checked locking pattern is correctly implemented and provides thread-safe lazy initialization with good performance characteristics.
Consider replacing the non-null assertion with a more defensive approach:
fun getClientApi(): ApiService { if (apiService == null) { synchronized(ConnectApiClient::class.java) { if (apiService == null) { apiService = buildRetrofitClient(BASE_URL).create(ApiService::class.java) } } } - return apiService!! + return apiService ?: throw IllegalStateException("ApiService should be initialized") }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt(1 hunks)app/src/org/commcare/connect/network/ApiConnect.java(0 hunks)app/src/org/commcare/connect/network/ApiEndPoints.java(2 hunks)app/src/org/commcare/connect/network/ApiPersonalId.java(9 hunks)app/src/org/commcare/connect/network/ApiService.java(2 hunks)app/src/org/commcare/connect/network/PersonalIdApiHandler.java(0 hunks)app/src/org/commcare/connect/network/base/BaseApiClient.kt(1 hunks)app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt(1 hunks)app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiHandler.kt(1 hunks)app/src/org/commcare/connect/network/connect/ConnectApiClient.kt(1 hunks)app/src/org/commcare/connect/network/connect/ConnectApiHandler.kt(1 hunks)app/src/org/commcare/connect/network/connect/parser/ConnectApiResponseParser.kt(1 hunks)app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt(1 hunks)app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt(1 hunks)app/src/org/commcare/connect/network/connectId/ApiClient.java(0 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiClient.java(1 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiErrorHandler.java(2 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/AddOrVerifyNameParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/CompleteProfileResponseParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/ConfirmBackupCodeResponseParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/PersonalIdApiResponseParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/StartConfigurationResponseParser.java(1 hunks)app/src/org/commcare/fragments/personalId/PersonalIdBackupCodeFragment.java(3 hunks)app/src/org/commcare/fragments/personalId/PersonalIdNameFragment.java(3 hunks)app/src/org/commcare/fragments/personalId/PersonalIdPhoneFragment.java(4 hunks)app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java(3 hunks)app/src/org/commcare/fragments/personalId/PersonalIdPhotoCaptureFragment.java(2 hunks)
💤 Files with no reviewable changes (3)
- app/src/org/commcare/connect/network/ApiConnect.java
- app/src/org/commcare/connect/network/connectId/ApiClient.java
- app/src/org/commcare/connect/network/PersonalIdApiHandler.java
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: shubham1g5
PR: dimagi/commcare-android#0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.
🪛 detekt (1.23.8)
app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt
[warning] 7-7: An empty default constructor can be removed.
(detekt.empty-blocks.EmptyDefaultConstructor)
app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt
[warning] 10-10: An empty default constructor can be removed.
(detekt.empty-blocks.EmptyDefaultConstructor)
app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt
[warning] 29-31: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
[warning] 33-35: This empty block of code can be removed.
(detekt.empty-blocks.EmptyFunctionBlock)
🔇 Additional comments (38)
app/src/org/commcare/connect/network/connect/parser/ConnectApiResponseParser.kt (1)
8-10: Clean and well-designed parser interface.The generic interface design provides good flexibility for different response types while maintaining a consistent parsing contract. The combination of response code and input stream parameters allows parsers to handle both HTTP status and response body appropriately.
app/src/org/commcare/connect/network/base/BaseApiClient.kt (1)
18-22: Good security practices for HTTP logging.The logging configuration properly handles debug vs release builds and redacts sensitive headers. This prevents accidental exposure of authentication tokens in production logs.
app/src/org/commcare/connect/network/connectId/parser/AddOrVerifyNameParser.java (1)
1-1: Package restructuring improves modularity.The move from generic
network.parsertoconnectId.parserpackage creates better separation between Connect API and Personal ID API concerns, improving code organization and maintainability.app/src/org/commcare/connect/network/connectId/parser/PersonalIdApiResponseParser.java (1)
1-1: Consistent with package restructuring strategy.This package change aligns with the broader refactoring to organize Personal ID API components under the
connectIdsubpackage, improving code organization and separation of concerns.app/src/org/commcare/connect/network/connectId/parser/CompleteProfileResponseParser.java (1)
1-1: Package change consistent with architectural refactoring.The move to
connectId.parserpackage maintains consistency with the broader restructuring effort to organize Personal ID API components.app/src/org/commcare/connect/network/connectId/parser/ConfirmBackupCodeResponseParser.java (1)
1-1: Package restructuring looks good.The package reorganization from
org.commcare.connect.network.parsertoorg.commcare.connect.network.connectId.parseraligns with the broader API client modularization mentioned in the PR objectives.app/src/org/commcare/connect/network/connectId/parser/StartConfigurationResponseParser.java (1)
1-1: Package restructuring is consistent.The package change aligns with the modularization pattern seen across the parser classes in this refactoring effort.
app/src/org/commcare/connect/network/ApiService.java (2)
1-1: Package restructuring aligns with the refactoring.Moving from
connectIdto the parentnetworkpackage is consistent with the API service consolidation.
35-36: New credential retrieval method is well-designed.The
retrieveCredentialsmethod follows proper Retrofit patterns with authorization header and appropriate return type. The POST annotation withApiEndPoints.CREDENTIALSendpoint is correctly implemented.app/src/org/commcare/connect/network/ApiEndPoints.java (2)
1-1: Package consolidation is appropriate.Moving endpoints to the parent
networkpackage centralizes API configuration, which is a good architectural decision.
19-19: New credentials endpoint constant is properly defined.The
CREDENTIALSconstant follows naming conventions and provides a logical endpoint path for credential retrieval functionality.app/src/org/commcare/connect/network/connectId/PersonalIdApiClient.java (2)
10-13: Verify the hard-coded BASE_URL and API_VERSION values.The hard-coded
BASE_URLand placeholderAPI_VERSIONcomment suggest these values need verification for different environments (dev, staging, production).Consider making the BASE_URL configurable or verify it's appropriate for all deployment environments.
18-27: Singleton implementation with double-checked locking is correct.The thread-safe singleton pattern is properly implemented with volatile field, synchronized block, and double-checked locking. The integration with
BaseApiClientcentralizes Retrofit configuration, which is a good architectural decision.app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt (1)
13-15: Good use of lazy binding initialization.The lazy initialization of the binding property is a clean improvement that simplifies lifecycle management.
app/src/org/commcare/connect/network/connectId/PersonalIdApiErrorHandler.java (2)
1-1: Package relocation aligns with API refactoring.The move to the
connectIdpackage properly organizes the PersonalId-specific error handling logic.
12-12: Updated error code references reflect unified API design.The change from
PersonalIdApiErrorCodestoPersonalIdOrConnectApiErrorCodesproperly reflects the new unified error handling approach for both PersonalId and Connect APIs.Also applies to: 29-29, 32-32
app/src/org/commcare/connect/network/connect/ConnectApiClient.kt (1)
14-14: Good use of BuildConfig for environment-specific configuration.Using
BuildConfig.CCC_HOSTallows for different base URLs across build variants, which is a best practice for API clients.app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java (3)
21-22: LGTM: Import updates align with package restructuring.The import statements correctly reference the new
connectIdpackage structure, consistent with the API handler refactor.
138-147: Good: Enhanced type safety and consistent error handling.The addition of the generic type parameter
<PersonalIdSessionData>improves type safety. The visibility changes fromprotectedtopublicfor the callback methods and the updated error code typePersonalIdOrConnectApiErrorCodesare consistent with the new unified API handler architecture.
326-326: LGTM: Error handling updated to use unified error codes.The method parameter type correctly uses the new
PersonalIdOrConnectApiErrorCodesenum for consistent error handling across the application.app/src/org/commcare/fragments/personalId/PersonalIdBackupCodeFragment.java (2)
24-25: LGTM: Consistent import updates.The import statements correctly reference the restructured
connectIdpackage, maintaining consistency with the broader API refactor.
200-222: Good: Consistent API handler modernization.The changes follow the same pattern as other fragments:
- Generic type parameter
<PersonalIdSessionData>for type safety- Method visibility changes from
protectedtopublic- Updated error code type to
PersonalIdOrConnectApiErrorCodesThis consistency demonstrates a well-coordinated refactor across the codebase.
app/src/org/commcare/connect/network/ApiPersonalId.java (4)
16-17: LGTM: Updated imports for new API client architecture.The imports correctly reference the new specialized API clients (
PersonalIdApiClientandConnectApiClient) as part of the architectural refactor.
87-87: Good: Consistent migration to PersonalIdApiClient.The BASE_URL references have been correctly updated to use
PersonalIdApiClient.BASE_URL, maintaining consistency in the migration from the legacy ApiClient.Also applies to: 108-108, 190-190
261-261: LGTM: API service calls updated to use new client pattern.All API service instantiations have been consistently updated to use
PersonalIdApiClient.getClientApi(), following the new architectural pattern.Also applies to: 268-268, 279-279, 292-292, 311-311, 329-329
334-340: ```shell
#!/bin/bashSearch for CCC_HOST definition across the repository
rg -n "CCC_HOST" -n .
Also search for BuildConfig field injection in build.gradle files
rg -n "buildConfigField.*CCC_HOST" -n .
</details> <details> <summary>app/src/org/commcare/connect/network/connect/ConnectApiHandler.kt (1)</summary> `1-50`: **Excellent: Well-designed Connect API handler with robust error handling.** This new Kotlin class demonstrates several strengths: - **Clean Architecture**: Properly extends `BasePersonalIdOrConnectApiHandler<T>` for consistency - **Separation of Concerns**: Uses parser abstraction (`ConnectApiResponseParser<T>`) for flexible response handling - **Comprehensive Error Handling**: Catches both `JSONException` and `IOException` with appropriate error codes - **Type Safety**: Leverages Kotlin generics effectively The `createCallback` method properly wraps exceptions in standardized error codes, and the `retrieveCredentials` method provides a clean interface for credential retrieval operations. </details> <details> <summary>app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiHandler.kt (1)</summary> `1-33`: **Excellent: Comprehensive base handler with intelligent error management.** This base class provides a solid foundation for the API refactor: **Strengths:** - **Complete Error Coverage**: The `PersonalIdOrConnectApiErrorCodes` enum covers all major failure scenarios (network, auth, server, parsing, rate limiting) - **Intelligent Retry Logic**: The `shouldAllowRetry()` method correctly identifies transient errors (network, server, token unavailable) as retryable while treating permanent errors (forbidden, parsing, auth) as non-retryable - **Clean Abstraction**: Abstract methods provide a consistent interface for both Personal ID and Connect API handlers - **Type Safety**: Generic type parameter `<T>` allows for type-safe response handling The error categorization is particularly well thought out, distinguishing between temporary issues that warrant retry attempts and permanent failures that require user intervention. </details> <details> <summary>app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt (1)</summary> `20-21`: **LGTM! Clean architecture with proper type safety.** The generic type parameter and base handler delegation provide good separation of concerns for centralized error handling. </details> <details> <summary>app/src/org/commcare/fragments/personalId/PersonalIdPhoneFragment.java (3)</summary> `32-33`: **LGTM! Updated imports align with the new modular architecture.** The move to the `connectId` subpackage reflects the improved organization of API handling classes. --- `215-216`: **LGTM! Updated error code enum provides broader coverage.** The change from `PersonalIdApiErrorCodes` to `PersonalIdOrConnectApiErrorCodes` aligns with the unified error handling approach across Personal ID and Connect APIs. --- `197-222`: Let’s locate the base handler class and inspect its method signatures to confirm required visibility: ```shell #!/bin/bash # Locate and inspect BasePersonalIdOrConnectApiHandler # 1. Find the file containing the class file=$(rg --files-with-matches "class BasePersonalIdOrConnectApiHandler") if [ -z "$file" ]; then echo "✗ BasePersonalIdOrConnectApiHandler not found in repo" exit 1 fi echo "✔ Found handler in: $file" echo echo "── Class declaration ───────────────────────────────────────────" rg -n "class BasePersonalIdOrConnectApiHandler" -C3 "$file" echo echo "── onSuccess signature(s) ───────────────────────────────────────" rg -n "onSuccess" -C2 "$file" echo echo "── onFailure signature(s) ───────────────────────────────────────" rg -n "onFailure" -C2 "$file"app/src/org/commcare/fragments/personalId/PersonalIdNameFragment.java (2)
21-22: LGTM! Consistent with the API handler refactor.The import updates to the
connectIdpackage maintain consistency with the modular architecture changes.
80-94: LGTM! Proper generic typing and error handling updates.The changes maintain consistency with the refactor:
- Generic type parameter
<PersonalIdSessionData>improves type safety- Updated error code enum aligns with the unified error handling approach
- Method visibility changes are consistent with the interface requirements
app/src/org/commcare/fragments/personalId/PersonalIdPhotoCaptureFragment.java (2)
28-29: LGTM! Consistent refactor implementation.The import updates to the
connectIdpackage are consistent with the modular API handling architecture.
88-101: LGTM! Proper alignment with the new API handler structure.The changes are consistent with the refactor pattern:
- Generic type parameter improves type safety
- Method visibility changes align with interface requirements
- Updated error code enum provides unified error handling
app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (2)
25-25: LGTM! Clean abstraction for Personal ID API handling.The abstract class design provides good separation of concerns and extends the base handler appropriately.
53-87: LGTM! Well-structured API method implementations.The public methods provide clear, focused interfaces for different API operations. The parser-based approach allows for flexible response handling while maintaining consistency.
| override fun parse(responseCode: Int, responseData: InputStream): T { | ||
| val success = responseCode in 200..299 | ||
| return success as T | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix unsafe type casting that could cause runtime exceptions.
The current implementation uses unsafe casting success as T, which assumes T is always Boolean. This will cause a ClassCastException if the parser is used with a different type parameter.
Consider one of these approaches:
Option 1: Constrain the generic type to Boolean
-class NoParsingResponseParser<T> : ConnectApiResponseParser<T> {
+class NoParsingResponseParser : ConnectApiResponseParser<Boolean> {
override fun parse(responseCode: Int, responseData: InputStream): Boolean {
val success = responseCode in 200..299
- return success as T
+ return success
}Option 2: Use @Suppress annotation with proper documentation
override fun parse(responseCode: Int, responseData: InputStream): T {
val success = responseCode in 200..299
+ @Suppress("UNCHECKED_CAST")
return success as T
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt
lines 9 to 12, the code unsafely casts a Boolean to the generic type T, risking
a ClassCastException if T is not Boolean. To fix this, constrain the generic
type T to Boolean in the class or method definition to ensure type safety, or
alternatively, if you must keep it generic, add a @Suppress annotation with
clear documentation explaining why the unchecked cast is safe in this context.
| override fun parse(responseCode: Int, responseData: InputStream): T { | ||
| val jsonArray = JSONArray(responseData) | ||
| return PersonalIdCredential.fromJsonArray(jsonArray) as T | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling and validate response code.
The current implementation has several issues:
- No validation of the
responseCodeparameter - No error handling for malformed JSON or stream reading failures
- Unsafe type casting similar to the NoParsingResponseParser
override fun parse(responseCode: Int, responseData: InputStream): T {
+ if (responseCode !in 200..299) {
+ throw RuntimeException("HTTP error: $responseCode")
+ }
+
+ return try {
+ val jsonString = responseData.bufferedReader().use { it.readText() }
- val jsonArray = JSONArray(responseData)
+ val jsonArray = JSONArray(jsonString)
- return PersonalIdCredential.fromJsonArray(jsonArray) as T
+ @Suppress("UNCHECKED_CAST")
+ PersonalIdCredential.fromJsonArray(jsonArray) as T
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to parse credentials response", e)
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| override fun parse(responseCode: Int, responseData: InputStream): T { | |
| val jsonArray = JSONArray(responseData) | |
| return PersonalIdCredential.fromJsonArray(jsonArray) as T | |
| } | |
| override fun parse(responseCode: Int, responseData: InputStream): T { | |
| if (responseCode !in 200..299) { | |
| throw RuntimeException("HTTP error: $responseCode") | |
| } | |
| return try { | |
| val jsonString = responseData.bufferedReader().use { it.readText() } | |
| val jsonArray = JSONArray(jsonString) | |
| @Suppress("UNCHECKED_CAST") | |
| PersonalIdCredential.fromJsonArray(jsonArray) as T | |
| } catch (e: Exception) { | |
| throw RuntimeException("Failed to parse credentials response", e) | |
| } | |
| } |
🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt
lines 12 to 15, add validation to check if responseCode indicates success before
parsing. Wrap the JSON parsing logic in a try-catch block to handle exceptions
from malformed JSON or stream errors. Replace the unsafe cast with a safer
approach, such as returning a nullable type or throwing a controlled exception
if parsing fails. Ensure all error cases are handled gracefully and provide
meaningful error messages or fallback behavior.
| override fun processFailure(responseCode: Int, errorResponse: InputStream?) { | ||
| if (responseCode == 401) { | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.FAILED_AUTH_ERROR, | ||
| null | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| if (responseCode == 403) { | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.FORBIDDEN_ERROR, | ||
| null | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| if (responseCode == 429 || responseCode == 503) { | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.RATE_LIMIT_EXCEEDED_ERROR, | ||
| null | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| if (responseCode == 500) { | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.SERVER_ERROR, | ||
| null | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| val info = StringBuilder("Response $responseCode") | ||
| if (errorResponse != null) { | ||
| try { | ||
| errorResponse.use { `in` -> | ||
| val json = | ||
| JSONObject(String(StreamsUtil.inputStreamToByteArray(`in`))) | ||
| if (json.has("error")) { | ||
| info.append(": ").append(json.optString("error")) | ||
| Toast.makeText( | ||
| CommCareApplication.instance(), json.optString("error"), | ||
| Toast.LENGTH_LONG | ||
| ).show() | ||
| } | ||
| } | ||
| } catch (e: JSONException) { | ||
| Logger.exception("Error parsing API error response", e) | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.UNKNOWN_ERROR, | ||
| e | ||
| ) | ||
| return | ||
| } catch (e: IOException) { | ||
| Logger.exception("Error parsing API error response", e) | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.UNKNOWN_ERROR, | ||
| e | ||
| ) | ||
| return | ||
| } | ||
| } | ||
| basePersonalIdOrConnectApiHandler.onFailure( | ||
| PersonalIdOrConnectApiErrorCodes.UNKNOWN_ERROR, | ||
| Exception(info.toString()) | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider UI context sensitivity for Toast notifications.
The error handling logic is comprehensive and well-structured. However, showing Toast messages directly from the callback (lines 65-68) might not be appropriate in all contexts, especially if the callback is triggered from background operations or when the activity is not in the foreground.
Consider moving Toast display logic to the handler level or making it configurable based on UI context.
- Toast.makeText(
- CommCareApplication.instance(), json.optString("error"),
- Toast.LENGTH_LONG
- ).show()
+ // Let the handler decide how to display the error
+ basePersonalIdOrConnectApiHandler.onFailure(
+ PersonalIdOrConnectApiErrorCodes.API_ERROR,
+ Exception(json.optString("error"))
+ )
+ return🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt
between lines 24 and 91, the Toast notification is shown directly inside the
callback when an error occurs, which can cause issues if the callback runs in a
background thread or when the UI is not active. To fix this, remove the Toast
display from the callback and instead delegate the responsibility of showing UI
notifications to the basePersonalIdOrConnectApiHandler or make the Toast display
configurable based on the UI context, ensuring that UI updates happen only when
the activity or fragment is in the foreground.
| private IApiCallback createCallback(PersonalIdSessionData sessionData, | ||
| PersonalIdApiResponseParser parser) { | ||
| return new BasePersonalIdOrConnectApiCallback<T>(this) { | ||
|
|
||
| @Override | ||
| public void processSuccess(int responseCode, InputStream responseData) { | ||
| if (parser != null) { | ||
| try (InputStream in = responseData) { | ||
| JSONObject json = new JSONObject(new String(StreamsUtil.inputStreamToByteArray(in))); | ||
| parser.parse(json, sessionData); | ||
| } catch (JSONException e) { | ||
| Logger.exception("JSON error parsing API response", e); | ||
| onFailure(PersonalIdOrConnectApiErrorCodes.JSON_PARSING_ERROR, e); | ||
| } catch (IOException e) { | ||
| Logger.exception("Error parsing API response", e); | ||
| onFailure(PersonalIdOrConnectApiErrorCodes.NETWORK_ERROR, e); | ||
| } | ||
| } | ||
| onSuccess((T)sessionData); | ||
| } | ||
|
|
||
|
|
||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix unsafe cast that could cause runtime exceptions.
The cast (T)sessionData on line 46 is unsafe and could cause ClassCastException at runtime. There's no guarantee that PersonalIdSessionData is assignable to type T.
Consider one of these solutions:
Solution 1: Add type bounds to ensure compatibility
-public abstract class PersonalIdApiHandler<T> extends BasePersonalIdOrConnectApiHandler<T> {
+public abstract class PersonalIdApiHandler<T extends PersonalIdSessionData> extends BasePersonalIdOrConnectApiHandler<T> {Solution 2: Remove generic type if not needed
-public abstract class PersonalIdApiHandler<T> extends BasePersonalIdOrConnectApiHandler<T> {
+public abstract class PersonalIdApiHandler extends BasePersonalIdOrConnectApiHandler<PersonalIdSessionData> {Solution 3: Add runtime type checking
- onSuccess((T)sessionData);
+ if (sessionData instanceof PersonalIdSessionData) {
+ onSuccess((T)sessionData);
+ } else {
+ onFailure(PersonalIdOrConnectApiErrorCodes.UNKNOWN_ERROR,
+ new ClassCastException("Invalid session data type"));
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java
between lines 28 and 51, the cast (T)sessionData is unsafe and may cause
ClassCastException. To fix this, either add appropriate generic type bounds to
ensure PersonalIdSessionData is compatible with T, or remove the generic type
parameter if it is unnecessary. Alternatively, implement a runtime type check
before casting to safely handle incompatible types and avoid exceptions.
📝 WalkthroughWalkthroughThis change refactors the network layer for personal ID and Connect API interactions by introducing new base handler and callback classes in Kotlin, standardizing error handling and response parsing. It replaces the old Sequence Diagram(s)sequenceDiagram
participant User
participant PersonalIdCredentialActivity
participant ConnectUserDatabaseUtil
participant ConnectApiHandler
participant ApiPersonalId
participant ConnectApiClient
participant ApiService
User->>PersonalIdCredentialActivity: Activity started
PersonalIdCredentialActivity->>ConnectUserDatabaseUtil: getCurrentUser()
ConnectUserDatabaseUtil-->>PersonalIdCredentialActivity: user
PersonalIdCredentialActivity->>ConnectApiHandler: retrieveCredentials(user)
ConnectApiHandler->>ApiPersonalId: retrieveCredentials(context, username, password, callback)
ApiPersonalId->>ConnectApiClient: getClientApi()
ConnectApiClient-->>ApiPersonalId: ApiService
ApiPersonalId->>ApiService: retrieveCredentials(Authorization)
ApiService-->>ApiPersonalId: Response
ApiPersonalId-->>ConnectApiHandler: callback.onSuccess/onFailure
ConnectApiHandler-->>PersonalIdCredentialActivity: onSuccess/onFailure
Possibly related PRs
Suggested labels
Suggested reviewers
✨ Finishing Touches
🧪 Generate Unit Tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
🧹 Nitpick comments (7)
app/src/org/commcare/connect/network/base/BaseApiClient.kt (1)
28-33: Consider making the Accept header format more explicit.The API version header construction could benefit from being more explicit about the media type format to improve maintainability.
Consider refactoring for better readability:
- requestWithHeadersBuilder.header( - "Accept", - "application/json;version=" + apiVersion - ) + val acceptHeader = "application/json;version=$apiVersion" + requestWithHeadersBuilder.header("Accept", acceptHeader)app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt (1)
7-7: Remove empty default constructor.The empty default constructor can be removed as noted by static analysis.
-class NoParsingResponseParser<T>() : ConnectApiResponseParser<T> { +class NoParsingResponseParser<T> : ConnectApiResponseParser<T> {app/src/org/commcare/connect/network/connect/ConnectApiClient.kt (1)
25-25: Avoid using the not-null assertion operator.The
!!operator can throwKotlinNullPointerException. Since we control the initialization with double-checked locking, this should never be null, but it's safer to use a more explicit approach.- return apiService!! + return apiService ?: throw IllegalStateException("ApiService not initialized")app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiHandler.kt (1)
26-29: Minor formatting improvement for readability.The boolean expression formatting could be improved for better readability.
- fun shouldAllowRetry(): Boolean { - return this == NETWORK_ERROR || (this == TOKEN_UNAVAILABLE_ERROR) || (this == SERVER_ERROR - ) || (this == UNKNOWN_ERROR) - } + fun shouldAllowRetry(): Boolean { + return this == NETWORK_ERROR || + this == TOKEN_UNAVAILABLE_ERROR || + this == SERVER_ERROR || + this == UNKNOWN_ERROR + }app/src/org/commcare/connect/network/connect/ConnectApiHandler.kt (1)
20-20: Remove unnecessary empty lines.The excessive spacing reduces code readability. Consider removing the empty lines for cleaner formatting.
- private fun createCallback( - parser: ConnectApiResponseParser<T>Also applies to: 39-39
app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt (1)
60-62: Avoid using backticks for variable names.Using
inas a variable name with backticks is valid but unconventional. Consider using a more descriptive name.- errorResponse.use { `in` -> - val json = - JSONObject(String(StreamsUtil.inputStreamToByteArray(`in`))) + errorResponse.use { stream -> + val json = + JSONObject(String(StreamsUtil.inputStreamToByteArray(stream)))app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java (1)
33-45: Consider improving error handling consistency.The error handling in
processSuccesscould be more consistent with the callback pattern by using the base callback's error handling methods.Instead of calling
onFailuredirectly, consider using the callback's built-in error processing:} catch (JSONException e) { Logger.exception("JSON error parsing API response", e); - onFailure(PersonalIdOrConnectApiErrorCodes.JSON_PARSING_ERROR, e); + basePersonalIdOrConnectApiHandler.onFailure(PersonalIdOrConnectApiErrorCodes.JSON_PARSING_ERROR, e); } catch (IOException e) { Logger.exception("Error parsing API response", e); - onFailure(PersonalIdOrConnectApiErrorCodes.NETWORK_ERROR, e); + basePersonalIdOrConnectApiHandler.onFailure(PersonalIdOrConnectApiErrorCodes.NETWORK_ERROR, e); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (28)
app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt(1 hunks)app/src/org/commcare/connect/network/ApiConnect.java(0 hunks)app/src/org/commcare/connect/network/ApiEndPoints.java(2 hunks)app/src/org/commcare/connect/network/ApiPersonalId.java(9 hunks)app/src/org/commcare/connect/network/ApiService.java(2 hunks)app/src/org/commcare/connect/network/PersonalIdApiHandler.java(0 hunks)app/src/org/commcare/connect/network/base/BaseApiClient.kt(1 hunks)app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt(1 hunks)app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiHandler.kt(1 hunks)app/src/org/commcare/connect/network/connect/ConnectApiClient.kt(1 hunks)app/src/org/commcare/connect/network/connect/ConnectApiHandler.kt(1 hunks)app/src/org/commcare/connect/network/connect/parser/ConnectApiResponseParser.kt(1 hunks)app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt(1 hunks)app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt(1 hunks)app/src/org/commcare/connect/network/connectId/ApiClient.java(0 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiClient.java(1 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiErrorHandler.java(2 hunks)app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/AddOrVerifyNameParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/CompleteProfileResponseParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/ConfirmBackupCodeResponseParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/PersonalIdApiResponseParser.java(1 hunks)app/src/org/commcare/connect/network/connectId/parser/StartConfigurationResponseParser.java(1 hunks)app/src/org/commcare/fragments/personalId/PersonalIdBackupCodeFragment.java(3 hunks)app/src/org/commcare/fragments/personalId/PersonalIdNameFragment.java(3 hunks)app/src/org/commcare/fragments/personalId/PersonalIdPhoneFragment.java(4 hunks)app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java(3 hunks)app/src/org/commcare/fragments/personalId/PersonalIdPhotoCaptureFragment.java(2 hunks)
💤 Files with no reviewable changes (3)
- app/src/org/commcare/connect/network/ApiConnect.java
- app/src/org/commcare/connect/network/connectId/ApiClient.java
- app/src/org/commcare/connect/network/PersonalIdApiHandler.java
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: shubham1g5
PR: dimagi/commcare-android#0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.
🪛 detekt (1.23.8)
app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt
[warning] 7-7: An empty default constructor can be removed.
(detekt.empty-blocks.EmptyDefaultConstructor)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Lint Code Base
🔇 Additional comments (39)
app/src/org/commcare/connect/network/base/BaseApiClient.kt (2)
15-46: Excellent implementation of centralized Retrofit client configuration.The BaseApiClient provides a solid foundation for API clients with proper security considerations, logging, and timeout configuration. The singleton pattern using Kotlin's
objectis appropriate for this utility class.Key strengths:
- Security-conscious logging with sensitive header redaction
- Environment-aware logging levels (debug vs release)
- Reasonable timeout configuration (30 seconds)
- Clean API version header injection logic
- Proper use of builder pattern for configuration
19-21: Good security practice with header redaction.The implementation correctly redacts sensitive headers like "Authorization" and "Cookie" from logs, which prevents accidental exposure of credentials in debug logs.
app/src/org/commcare/connect/network/connectId/parser/AddOrVerifyNameParser.java (1)
1-1: Good architectural decision with package restructuring.Moving the parser to the
connectId.parserpackage improves code organization by grouping personal ID-related components together. This aligns well with the broader API refactoring effort.app/src/org/commcare/connect/network/connectId/parser/PersonalIdApiResponseParser.java (1)
1-1: Consistent package organization for the parser interface.Moving the core
PersonalIdApiResponseParserinterface to theconnectId.parserpackage maintains consistency with the other parser implementations and improves module cohesion.app/src/org/commcare/connect/network/connectId/parser/CompleteProfileResponseParser.java (2)
1-1: Package relocation supports improved module organization.The move to
connectId.parserpackage is consistent with the other parser relocations and supports better separation of personal ID API concerns.
23-25: Excellent use of null-safety for required fields.The use of
Objects.requireNonNull()for critical fields likeusername,db_key, andpasswordensures fail-fast behavior if the API response is missing required data, which improves debugging and prevents silent failures.app/src/org/commcare/connect/network/connectId/parser/ConfirmBackupCodeResponseParser.java (2)
1-1: Final parser relocated to maintain package consistency.The package move completes the consistent reorganization of personal ID parsers under the
connectId.parsernamespace.
21-27: Good defensive programming with optional field handling.The implementation correctly handles the optional
attempts_leftfield with conditional parsing and uses safe string extraction methods to prevent parsing errors. This makes the parser robust against API response variations.app/src/org/commcare/connect/network/connectId/parser/StartConfigurationResponseParser.java (1)
1-1: LGTM: Package restructuring improves organization.The package move to
org.commcare.connect.network.connectId.parseraligns with the broader refactoring to separate PersonalId and Connect API components into distinct subpackages.app/src/org/commcare/connect/network/ApiService.java (2)
1-1: LGTM: Package centralization improves structure.Moving
ApiServiceto the main network package makes it accessible to both PersonalId and Connect API clients.
35-36: LGTM: New credential retrieval method follows established patterns.The
retrieveCredentialsmethod is properly designed with:
- Consistent Authorization header parameter
- Appropriate return type matching other methods
- No request body for GET-like operations
app/src/org/commcare/connect/network/ApiEndPoints.java (2)
1-1: LGTM: Package centralization for shared constants.Moving
ApiEndPointsto the main network package allows both PersonalId and Connect API components to access these shared constants.
19-19: LGTM: New endpoint constant follows established conventions.The
CREDENTIALSconstant follows the existing naming pattern and REST API conventions for user-related endpoints.app/src/org/commcare/connect/network/connect/parser/ConnectApiResponseParser.kt (1)
1-10: LGTM: Well-designed response parser interface.The interface provides a clean, generic contract for parsing Connect API responses with:
- Appropriate method signature for HTTP response handling
- Generic type parameter for flexibility
- Clear documentation
- Efficient use of InputStream for data processing
app/src/org/commcare/connect/network/connectId/PersonalIdApiClient.java (1)
22-22: ```shell
#!/bin/bashDisplay the full buildRetrofitClient method implementation to verify apiVersion usage
rg -n -A 20 "fun buildRetrofitClient" app/src/org/commcare/connect/network/base/BaseApiClient.kt
</details> <details> <summary>app/src/org/commcare/connect/network/connectId/PersonalIdApiErrorHandler.java (2)</summary> `1-1`: **Package refactoring aligns with modular architecture.** The package change to `connectId` subpackage improves code organization and separates personal ID specific error handling from generic network error handling. --- `32-33`: **Error code enum unification improves consistency.** The updated method signature using `PersonalIdOrConnectApiErrorCodes` allows this handler to work with both Personal ID and Connect APIs, promoting code reuse and consistency. </details> <details> <summary>app/src/org/commcare/connect/network/connect/ConnectApiClient.kt (1)</summary> `21-21`: ```shell #!/bin/bash # Search for API_VERSION definition and usage rg -n "API_VERSION" --color=neverapp/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiHandler.kt (2)
6-10: Well-designed base abstraction for API handlers.The abstract base class provides a clean separation of concerns and allows for consistent error handling across different API implementations. The generic type parameter enables type-safe response handling.
13-30: Comprehensive error code enumeration with retry logic.The error codes cover all common API failure scenarios, and the
shouldAllowRetry()method centralizes retry decision logic. This promotes consistent behavior across all API handlers.app/src/org/commcare/connect/network/connect/ConnectApiHandler.kt (2)
21-38: LGTM - Well structured callback creation.The callback implementation properly handles JSON parsing and IO exceptions with appropriate error codes and logging.
41-47: ```shell
#!/bin/bashDisplay RetrieveCredentialsResponseParser implementation
sed -n '1,200p' app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt
</details> <details> <summary>app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt (2)</summary> `13-15`: **Good improvement using lazy binding.** The switch from nullable binding to lazy property simplifies lifecycle management and eliminates the need to nullify in `onDestroy`. --- `13-15`: **Good improvement to view binding lifecycle management.** Changing from a nullable variable to a lazy property eliminates the need for null checks and manual cleanup in `onDestroy`. </details> <details> <summary>app/src/org/commcare/fragments/personalId/PersonalIdPhoneVerificationFragment.java (4)</summary> `326-326`: **Update method parameter type consistently.** The parameter type was correctly updated to match the new error code enum. --- `21-22`: **Verify the package structure change.** The imports changed from the `network` package to the `connectId` subpackage. Ensure this aligns with the overall API refactoring and that the new classes provide equivalent functionality. ```shell #!/bin/bash # Description: Verify the new connectId package classes exist and provide the expected functionality # Check if the new PersonalIdApiHandler class exists in connectId package fd "PersonalIdApiHandler" --type f | grep connectId # Check if PersonalIdApiErrorHandler exists in connectId package fd "PersonalIdApiErrorHandler" --type f | grep connectId
138-147: ```shell
#!/usr/bin/env bashVerify existence of the PersonalIdOrConnectApiErrorCodes enum
rg "enum PersonalIdOrConnectApiErrorCodes" -n .
List all references to PersonalIdOrConnectApiErrorCodes
rg "PersonalIdOrConnectApiErrorCodes" -n .
Locate the PersonalIdApiHandler class definition
rg "class PersonalIdApiHandler" -n .
Show the signature for validateFirebaseIdToken across the codebase
rg "validateFirebaseIdToken" -n .
--- `21-22`: **LGTM! Consistent API refactoring implementation.** The changes properly migrate to the new API client architecture: - Updated imports to use the `connectId` package - Added proper generic typing to `PersonalIdApiHandler<PersonalIdSessionData>` - Updated error code type to `PersonalIdOrConnectApiErrorCodes` - Changed method visibility to `public` for callback implementation Also applies to: 138-138, 140-140, 144-144, 326-326 </details> <details> <summary>app/src/org/commcare/fragments/personalId/PersonalIdBackupCodeFragment.java (3)</summary> `24-25`: **LGTM - Consistent with API refactoring.** The import changes align with the broader refactoring to move API handlers to the `connectId` package. --- `200-222`: **LGTM - Proper generic typing and error handling updates.** The changes correctly add generic typing and update the error code enum to match the new architecture. The method visibility changes are consistent with the new API pattern. --- `24-25`: **LGTM! Consistent with API refactoring pattern.** The changes align with the overall migration to the new API client architecture, including updated imports, generic typing, and error code types. Also applies to: 200-200, 202-202, 215-215 </details> <details> <summary>app/src/org/commcare/connect/network/ApiPersonalId.java (5)</summary> `16-17`: **LGTM - Import updates align with API client refactoring.** The imports correctly reference the new `PersonalIdApiClient` and `ConnectApiClient` classes replacing the old `ApiClient`. --- `87-87`: **LGTM - Consistent BASE_URL updates.** All references to `ApiClient.BASE_URL` have been correctly updated to `PersonalIdApiClient.BASE_URL`. Also applies to: 108-108, 190-190 --- `261-261`: **LGTM - API service calls updated consistently.** All API service instances are now obtained via `PersonalIdApiClient.getClientApi()` instead of the removed `ApiClient.getClientApi()`. Also applies to: 268-268, 279-279, 292-292, 311-311, 329-329 --- `16-17`: **LGTM! Consistent migration to new API clients.** The changes properly update all references from the removed `ApiClient` to the new `PersonalIdApiClient` and `ConnectApiClient` classes, maintaining consistent API usage patterns. Also applies to: 87-87, 108-108, 190-190, 261-261, 268-268, 279-279, 292-292, 311-311, 329-329 --- `334-340`: ```shell #!/bin/bash echo "Searching for 'retrieveCredentials' in .java and .kt files..." rg -n "retrieveCredentials" --no-messages --glob '*.java' --glob '*.kt'app/src/org/commcare/fragments/personalId/PersonalIdPhotoCaptureFragment.java (1)
28-29: LGTM! Refactoring changes are consistent.The migration to the new API handler structure with explicit generic typing and updated error codes is properly implemented.
Also applies to: 88-110
app/src/org/commcare/fragments/personalId/PersonalIdNameFragment.java (1)
21-22: LGTM! Consistent refactoring pattern applied.The changes properly integrate with the new API handler architecture, maintaining consistency across fragments.
Also applies to: 80-103
app/src/org/commcare/fragments/personalId/PersonalIdPhoneFragment.java (1)
32-33: LGTM! Proper null safety annotations added.The refactoring is consistent with other fragments, and the addition of
@Nullableannotations improves null safety.Also applies to: 197-242
| override fun parse(responseCode: Int, responseData: InputStream): T { | ||
| val success = responseCode in 200..299 | ||
| return success as T | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix unsafe type casting that could cause runtime exceptions.
The unsafe cast success as T will cause a ClassCastException if the calling code expects any type other than Boolean.
Consider these solutions:
Solution 1 (Recommended): Make it Boolean-specific
-class NoParsingResponseParser<T> : ConnectApiResponseParser<T> {
+class NoParsingResponseParser : ConnectApiResponseParser<Boolean> {
- override fun parse(responseCode: Int, responseData: InputStream): T {
+ override fun parse(responseCode: Int, responseData: InputStream): Boolean {
val success = responseCode in 200..299
- return success as T
+ return success
}Solution 2: Add type safety check
override fun parse(responseCode: Int, responseData: InputStream): T {
val success = responseCode in 200..299
- return success as T
+ @Suppress("UNCHECKED_CAST")
+ return success as T // Note: Only safe when T is Boolean
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| override fun parse(responseCode: Int, responseData: InputStream): T { | |
| val success = responseCode in 200..299 | |
| return success as T | |
| } | |
| // Change the class to only ever produce Boolean results | |
| class NoParsingResponseParser : ConnectApiResponseParser<Boolean> { | |
| override fun parse(responseCode: Int, responseData: InputStream): Boolean { | |
| val success = responseCode in 200..299 | |
| return success | |
| } | |
| } |
🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/connect/parser/NoParsingResponseParser.kt
lines 9 to 12, the code unsafely casts a Boolean to a generic type T, risking a
ClassCastException. To fix this, restrict the parser to return Boolean
explicitly by changing the return type to Boolean and returning the success
variable directly, or alternatively, add a type check to ensure T is Boolean
before casting and handle other types safely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on returning a boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shubham1g5 Perfect! That's the right approach for type safety. Removing the generic type parameter and returning Boolean directly will prevent any potential ClassCastException at runtime while keeping the API clean and predictable.
🐰✨ excited rabbit with sparkles
🧠 Learnings used
Learnt from: shubham1g5
PR: dimagi/commcare-android#0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL | ||
| private static final String API_VERSION = "1.0"; // Replace with actual version value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace hardcoded URLs and version with configuration.
The hardcoded BASE_URL and API_VERSION values should be moved to a configuration system (BuildConfig, properties, or environment variables) to support different environments and avoid production issues.
- public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL
- private static final String API_VERSION = "1.0"; // Replace with actual version value
+ public static final String BASE_URL = BuildConfig.PERSONAL_ID_BASE_URL;
+ private static final String API_VERSION = BuildConfig.PERSONAL_ID_API_VERSION;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL | |
| private static final String API_VERSION = "1.0"; // Replace with actual version value | |
| public static final String BASE_URL = BuildConfig.PERSONAL_ID_BASE_URL; | |
| private static final String API_VERSION = BuildConfig.PERSONAL_ID_API_VERSION; |
🤖 Prompt for AI Agents
In app/src/org/commcare/connect/network/connectId/PersonalIdApiClient.java
around lines 11 to 12, the BASE_URL and API_VERSION are hardcoded, which reduces
flexibility for different environments. Refactor the code to load these values
from a configuration source such as BuildConfig fields, properties files, or
environment variables. Replace the hardcoded strings with references to these
configuration values to enable easier environment-specific customization.
| /** | ||
| * Parser for retrieving credentials response | ||
| */ | ||
| class RetrieveCredentialsResponseParser<T>() : ConnectApiResponseParser<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider constraining the generic type parameter.
The generic type T should be bounded to ensure type safety. Consider constraining it to the expected return type.
-class RetrieveCredentialsResponseParser<T>() : ConnectApiResponseParser<T> {
+class RetrieveCredentialsResponseParser<T : List<PersonalIdCredential>>() : ConnectApiResponseParser<T> {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| class RetrieveCredentialsResponseParser<T>() : ConnectApiResponseParser<T> { | |
| class RetrieveCredentialsResponseParser<T : List<PersonalIdCredential>>() : ConnectApiResponseParser<T> { |
🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt
at line 10, the generic type parameter T is currently unconstrained, which can
lead to type safety issues. Modify the class declaration to constrain T to the
expected return type or interface that T should extend or implement, ensuring
that only appropriate types are used with this parser.
| override fun parse(responseCode: Int, responseData: InputStream): T { | ||
| val jsonArray = JSONArray(responseData) | ||
| return PersonalIdCredential.fromJsonArray(jsonArray) as T | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix unsafe type casting and add error handling.
The implementation has several critical issues:
- Unsafe casting: Casting
PersonalIdCredential.fromJsonArray(jsonArray) as Twithout type checking can causeClassCastExceptionat runtime - Missing error handling: No exception handling for JSON parsing or stream reading failures
- No null safety: InputStream could be null or empty
- override fun parse(responseCode: Int, responseData: InputStream): T {
- val jsonArray = JSONArray(responseData)
- return PersonalIdCredential.fromJsonArray(jsonArray) as T
- }
+ override fun parse(responseCode: Int, responseData: InputStream): T {
+ try {
+ val jsonString = responseData.bufferedReader().use { it.readText() }
+ val jsonArray = JSONArray(jsonString)
+ val result = PersonalIdCredential.fromJsonArray(jsonArray)
+ @Suppress("UNCHECKED_CAST")
+ return result as T
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to parse credentials response", e)
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| override fun parse(responseCode: Int, responseData: InputStream): T { | |
| val jsonArray = JSONArray(responseData) | |
| return PersonalIdCredential.fromJsonArray(jsonArray) as T | |
| } | |
| override fun parse(responseCode: Int, responseData: InputStream): T { | |
| try { | |
| val jsonString = responseData.bufferedReader().use { it.readText() } | |
| val jsonArray = JSONArray(jsonString) | |
| val result = PersonalIdCredential.fromJsonArray(jsonArray) | |
| @Suppress("UNCHECKED_CAST") | |
| return result as T | |
| } catch (e: Exception) { | |
| throw RuntimeException("Failed to parse credentials response", e) | |
| } | |
| } |
🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/connect/parser/RetrieveCredentialsResponseParser.kt
around lines 12 to 15, fix the unsafe cast by verifying the type before casting
or using a safer approach to convert the JSON array to the expected type T. Add
try-catch blocks to handle exceptions from JSON parsing and InputStream reading
to prevent crashes. Also, check if the InputStream is null or empty before
parsing and handle those cases appropriately to ensure null safety.
|
|
||
| companion object { | ||
|
|
||
| val BASE_URL: String = "https://${BuildConfig.CCC_HOST}" // Replace with actual base URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Make base URL construction more robust.
The string interpolation for BASE_URL could fail if BuildConfig.CCC_HOST is null or empty. Consider adding validation.
- val BASE_URL: String = "https://${BuildConfig.CCC_HOST}" // Replace with actual base URL
+ val BASE_URL: String = "https://${BuildConfig.CCC_HOST.takeIf { it.isNotEmpty() } ?: "default-host.com"}"Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In app/src/org/commcare/connect/network/connect/ConnectApiClient.kt at line 14,
the BASE_URL is constructed using string interpolation without validating if
BuildConfig.CCC_HOST is null or empty, which could cause runtime issues. Add a
check to ensure BuildConfig.CCC_HOST is not null or empty before constructing
BASE_URL, and handle the invalid case by either throwing an exception or
providing a default/fallback URL to make the base URL construction more robust.
| Toast.makeText( | ||
| CommCareApplication.instance(), json.optString("error"), | ||
| Toast.LENGTH_LONG | ||
| ).show() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove UI dependency from base network class.
Showing Toast messages directly from a base network handler class creates tight coupling with the UI layer and makes unit testing difficult. Consider returning error messages to the caller instead.
Instead of showing Toast directly, consider passing the error message to the handler:
- if (json.has("error")) {
- info.append(": ").append(json.optString("error"))
- Toast.makeText(
- CommCareApplication.instance(), json.optString("error"),
- Toast.LENGTH_LONG
- ).show()
- }
+ if (json.has("error")) {
+ val errorMessage = json.optString("error")
+ info.append(": ").append(errorMessage)
+ basePersonalIdOrConnectApiHandler.onFailure(
+ PersonalIdOrConnectApiErrorCodes.API_ERROR_WITH_MESSAGE,
+ Exception(errorMessage)
+ )
+ return
+ }🤖 Prompt for AI Agents
In
app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt
around lines 65 to 68, remove the direct Toast UI call from the base network
class to decouple UI from network logic. Instead of showing the Toast here,
modify the method to return or pass the error message string to the caller or a
callback handler, so the UI layer can decide how to display it. This will
improve testability and separation of concerns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shubham1g5 Thanks for confirming! Great to see agreement on improving the separation of concerns by removing the Toast dependency from the base network class. This refactoring will definitely make the code more testable and maintainable.
🧠 Learnings used
Learnt from: shubham1g5
PR: dimagi/commcare-android#0
File: :0-0
Timestamp: 2025-05-08T11:08:18.530Z
Learning: PR #3048 "Phase 4 Connect PR" introduces a substantial feature called "Connect" to the CommCare Android app, which includes messaging, job management, delivery tracking, payment processing, authentication flows, and learning modules. It follows a modern architecture using Navigation Components with three navigation graphs, segregated business logic in Manager classes, and proper database persistence.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| import java.io.InputStream; | ||
| import java.util.Map; | ||
|
|
||
| public abstract class PersonalIdApiHandler<T> extends BasePersonalIdOrConnectApiHandler<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add type constraint to prevent runtime ClassCastException.
The unchecked cast (T)sessionData on line 46 could cause a ClassCastException at runtime if T is not compatible with PersonalIdSessionData. Consider adding a type constraint to the generic parameter.
Apply this fix to add type safety:
-public abstract class PersonalIdApiHandler<T> extends BasePersonalIdOrConnectApiHandler<T> {
+public abstract class PersonalIdApiHandler<T extends PersonalIdSessionData> extends BasePersonalIdOrConnectApiHandler<T> {This ensures that T must be PersonalIdSessionData or a subtype, making the cast safe.
Also applies to: 46-46
🤖 Prompt for AI Agents
In app/src/org/commcare/connect/network/connectId/PersonalIdApiHandler.java at
line 25, add a type constraint to the generic parameter T so that it extends
PersonalIdSessionData. This will ensure that the unchecked cast to
(T)sessionData on line 46 is safe and prevent potential ClassCastException at
runtime. Modify the class declaration to enforce this constraint.
| onFailure(PersonalIdOrConnectApiErrorCodes.JSON_PARSING_ERROR, e) | ||
| } catch (e: IOException) { | ||
| Logger.exception("Error parsing API response", e) | ||
| onFailure(PersonalIdOrConnectApiErrorCodes.NETWORK_ERROR, e) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing import for PersonalIdOrConnectApiErrorCodes.
The code references PersonalIdOrConnectApiErrorCodes.JSON_PARSING_ERROR and PersonalIdOrConnectApiErrorCodes.NETWORK_ERROR but doesn't import the enum class. This will cause compilation errors.
Add the missing import:
import org.commcare.connect.network.connect.parser.ConnectApiResponseParser
import org.commcare.connect.network.connect.parser.RetrieveCredentialsResponseParser
+import org.commcare.connect.network.base.BasePersonalIdOrConnectApiHandler.PersonalIdOrConnectApiErrorCodes
import org.javarosa.core.services.Logger🤖 Prompt for AI Agents
In app/src/org/commcare/connect/network/connect/ConnectApiHandler.kt around
lines 30 to 33, the enum class PersonalIdOrConnectApiErrorCodes is used but not
imported, causing compilation errors. Add the appropriate import statement for
PersonalIdOrConnectApiErrorCodes at the top of the file to resolve the missing
reference.
|
|
||
| } | ||
|
|
||
| override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing import for PersonalIdOrConnectApiErrorCodes.
The onFailure method parameter uses PersonalIdOrConnectApiErrorCodes but this type is not imported, which will cause compilation errors.
Add the missing import:
import org.commcare.connect.database.ConnectUserDatabaseUtil
import org.commcare.connect.network.connect.ConnectApiHandler
+import org.commcare.connect.network.base.BasePersonalIdOrConnectApiHandler.PersonalIdOrConnectApiErrorCodes
import org.commcare.dalvik.R📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) { | |
| import org.commcare.connect.database.ConnectUserDatabaseUtil | |
| import org.commcare.connect.network.connect.ConnectApiHandler | |
| import org.commcare.connect.network.base.BasePersonalIdOrConnectApiHandler.PersonalIdOrConnectApiErrorCodes | |
| import org.commcare.dalvik.R |
🤖 Prompt for AI Agents
In app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt at
line 33, the type PersonalIdOrConnectApiErrorCodes used in the onFailure method
parameter is not imported, causing compilation errors. Add the appropriate
import statement for PersonalIdOrConnectApiErrorCodes at the top of the file to
resolve this issue.
| object : ConnectApiHandler<PersonalIdValidAndCorruptCredential>() { | ||
| override fun onSuccess(personalIdValidAndCorruptCredential: PersonalIdValidAndCorruptCredential) { | ||
|
|
||
| } | ||
|
|
||
| override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) { | ||
|
|
||
| } | ||
| }.retrieveCredentials(this, user.name, user.password) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement meaningful success and failure handlers.
The anonymous ConnectApiHandler has empty onSuccess and onFailure methods, making the API call effectively useless. The credentials are retrieved but not processed.
Consider implementing the handlers to process the retrieved credentials:
object : ConnectApiHandler<PersonalIdValidAndCorruptCredential>() {
override fun onSuccess(personalIdValidAndCorruptCredential: PersonalIdValidAndCorruptCredential) {
-
+ // Process the retrieved credentials
+ // e.g., update UI, store in database, navigate to next screen
}
override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) {
-
+ // Handle the failure
+ // e.g., show error message, retry logic, log error
}
}.retrieveCredentials(this, user.name, user.password)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| object : ConnectApiHandler<PersonalIdValidAndCorruptCredential>() { | |
| override fun onSuccess(personalIdValidAndCorruptCredential: PersonalIdValidAndCorruptCredential) { | |
| } | |
| override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) { | |
| } | |
| }.retrieveCredentials(this, user.name, user.password) | |
| object : ConnectApiHandler<PersonalIdValidAndCorruptCredential>() { | |
| override fun onSuccess(personalIdValidAndCorruptCredential: PersonalIdValidAndCorruptCredential) { | |
| // Process the retrieved credentials | |
| // e.g., update UI, store in database, navigate to next screen | |
| } | |
| override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) { | |
| // Handle the failure | |
| // e.g., show error message, retry logic, log error | |
| } | |
| }.retrieveCredentials(this, user.name, user.password) |
🤖 Prompt for AI Agents
In app/src/org/commcare/activities/connect/PersonalIdCredentialActivity.kt
around lines 28 to 36, the ConnectApiHandler's onSuccess and onFailure methods
are empty, so the retrieved credentials are not processed. Implement onSuccess
to handle the valid credentials appropriately, such as updating the UI or
storing the data, and implement onFailure to handle errors by showing error
messages or retry logic. This will make the API call meaningful by processing
the results or handling failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall, left some minor suggestions inline with Code Rabbit comments on the PR.
app/src/org/commcare/connect/network/base/BasePersonalIdOrConnectApiCallback.kt
Outdated
Show resolved
Hide resolved
| try { | ||
| errorResponse.use { `in` -> | ||
| val json = | ||
| JSONObject(String(StreamsUtil.inputStreamToByteArray(`in`))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
| Toast.makeText( | ||
| CommCareApplication.instance(), json.optString("error"), | ||
| Toast.LENGTH_LONG | ||
| ).show() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
app/src/org/commcare/connect/network/connect/ConnectApiClient.kt
Outdated
Show resolved
Hide resolved
| override fun parse(responseCode: Int, responseData: InputStream): T { | ||
| val success = responseCode in 200..299 | ||
| return success as T | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 on returning a boolean.
| } | ||
|
|
||
|
|
||
| fun retrieveCredentials(context: Context, userName: String, password: String) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
think this should be part of PersonalIdApiHandler given we are querying the personalID server here.
| * Retrofit client for personalId API | ||
| */ | ||
| public class PersonalIdApiClient { | ||
| public static final String BASE_URL = "https://connectid.dimagi.com"; // Replace with actual base URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can remove // Replace with actual base URL here as well.
|
|
||
| override fun parse(responseCode: Int, responseData: InputStream): T { | ||
| val success = responseCode in 200..299 | ||
| return success as T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Jignesh-dimagi think we should return a boolean from here as it will crash otherwise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shubham1g5 This is generic parser created to return the Boolean when calling the handler. I have created here as devs can directly use it.
object : ConnectApiHandler<Boolean>() {
override fun onSuccess(success: Boolean) {
}
override fun onFailure(failureCode: PersonalIdOrConnectApiErrorCodes, t: Throwable?) {
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applying anything other than <Boolean> to this would crash on line return success as T , so having a generic type parmeter here is not really serving a pupose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the base of parsing, it's required to determine which object will be returned after parsing. Same as we provide data class to retrofit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the statement responseCode in 200..299 always returns a boolean right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it should but here it is used as medium to return the call to fragment/activity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I now see that you are inheriting it from the BaseApiResponseParser which is what's forcing this to be generified which makes sense to me, although I don't see the NoParsingResponseParser used anywhere at the moment. Do you have any upcoming usage in mind for this ? Otherwise we should not really be introducing unused classes in the code base.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree and you are correct for unused classed as not used now but will be used extensively whenever app will have API where it used it to update/insert and interested response is just boolean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool sounds good to keep it for now.
Technical Summary
https://dimagi.atlassian.net/browse/CCCT-1323
Feature Flag
Introducing Retrofit,Api handlers, callbacks for connect API calling
Labels and Review