Abhishek Chaudhary created FINERACT-2671:
--------------------------------------------

             Summary: Client family member and GSIM account lookups return HTTP 
500 instead of 404 when the record does not exist
                 Key: FINERACT-2671
                 URL: https://issues.apache.org/jira/browse/FINERACT-2671
             Project: Apache Fineract
          Issue Type: Bug
          Components: Client, Savings
    Affects Versions: 1.14.0
            Reporter: Abhishek Chaudhary


*Observed behavior*

Two read endpoints return a raw HTTP 500 due to an unhandled 
{{EmptyResultDataAccessException}} when the requested resource does not exist:

{noformat}
GET /fineract-provider/api/v1/clients/{clientId}/familymembers/{familyMemberId}
GET /fineract-provider/api/v1/groups/{groupId}/gsimaccounts?parentGSIMId={id}
{noformat}

This can be reproduced on the current {{develop}} branch and is also present in 
{{1.14.0}}.

*Root cause*

* {{ClientFamilyMembersReadPlatformServiceImpl.getClientFamilyMember()}} calls 
{{jdbcTemplate.queryForObject(...)}} without handling the case where no rows 
are returned.
* {{GSIMReadPlatformServiceImpl.findGSIMAccountByGSIMId()}} follows the same 
pattern. It is invoked from {{GroupsApiResource.retrieveGsimAccounts()}} 
whenever the {{parentGSIMId}} query parameter is supplied.

When {{JdbcTemplate.queryForObject()}} finds no matching row, Spring throws 
{{EmptyResultDataAccessException}}. Since there is no dedicated exception 
mapper for it under 
{{org.apache.fineract.infrastructure.core.exceptionmapper}}, it falls through 
to {{DefaultExceptionMapper}}, resulting in an HTTP 500 instead of a 404.

*Additional defect (Family Members)*

The family-member lookup does not validate the {{clientId}} path parameter. The 
query filters only by {{fmb.id}}, meaning requests such as:

{noformat}
GET /clients/999/familymembers/5
{noformat}

can return a family member belonging to a different client.

The lookup should instead be scoped as:

{code:sql}
WHERE fmb.client_id = ? AND fmb.id = ?
{code}

If the family member does not belong to the client specified in the path, the 
endpoint should return HTTP 404.

*Expected behavior*

Both endpoints should return HTTP 404 with the standard platform error payload 
when the requested resource does not exist.

This should follow the existing Fineract pattern:

* Catch {{EmptyResultDataAccessException}}.
* Throw a domain-specific exception extending 
{{AbstractPlatformResourceNotFoundException}}.
* Let {{PlatformResourceNotFoundExceptionMapper}} translate it into an HTTP 404 
response.

*Steps to reproduce*

# Call:

{noformat}
GET /fineract-provider/api/v1/clients/1/familymembers/999999
{noformat}

Current: HTTP 500

Expected: HTTP 404

# Call:

{noformat}
GET /fineract-provider/api/v1/groups/1/gsimaccounts?parentGSIMId=999999
{noformat}

Current: HTTP 500

Expected: HTTP 404

# Create Client A with a family member M and Client B. Then call:

{noformat}
GET /clients/{B}/familymembers/{M}
{noformat}

Current: Returns the family member belonging to Client A.

Expected: HTTP 404.

*Proposed fix*

* Introduce {{FamilyMemberNotFoundException}} and 
{{GSIMAccountNotFoundException}}, both extending 
{{AbstractPlatformResourceNotFoundException}}.
* Catch {{EmptyResultDataAccessException}} in the corresponding read-platform 
service methods and rethrow the appropriate domain-specific exception.
* Scope the family-member lookup by both {{client_id}} and {{familyMemberId}}.
* Add integration tests covering:
** Non-existent family member → HTTP 404.
** Non-existent GSIM account → HTTP 404.
** Family member belonging to a different client → HTTP 404.

I found this issue while reviewing the read-platform services and would like to 
work on it. Please assign it to me.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to