Farooq Ayoade created FINERACT-2776:
---------------------------------------

             Summary: GET /datatables response schema omits entitySubType, so 
generated clients cannot read it
                 Key: FINERACT-2776
                 URL: https://issues.apache.org/jira/browse/FINERACT-2776
             Project: Apache Fineract
          Issue Type: Bug
          Components: System
            Reporter: Farooq Ayoade


h3. Summary

{{POST /datatables}} accepts an {{entitySubType}} and the platform stores it in
{{x_registered_table.entity_subtype}}. Both GET routes return it at runtime: 
{{DatatableData}} carries the
field, and {{DatatableReadServiceImpl}} selects {{entity_subtype}} and passes 
it into
{{DatatableData.create(...)}} on the list path and the single-table path alike.

The one place it does not appear is the class both routes name as their 
{{@ApiResponse}} schema.
{{DatatablesApiResourceSwagger.PostDataTablesRequest}} declares 
{{entitySubType}};
{{GetDataTablesResponse}} does not. The published OpenAPI document therefore 
describes a datatable as
having only {{applicationTableName}}, {{registeredTableName}} and 
{{columnHeaderData}}.

The asymmetry is the bug: the API lets a caller *set* a property and then 
documents a response in which
that property does not exist.

h3. Impact

A hand-written client never notices, because the JSON has the field. A 
generated client cannot read it at
all -- the member is not on the type, so the natural workaround is to cast away 
the generated type at
exactly the point where it is most worth having.

That matters because of what the field is for. {{entitySubType}} scopes a 
datatable to a client legal form
(Person / Entity), so a UI rendering custom fields on a customer has to read it 
to know whether a given
table belongs on an individual or on a corporate. Without it, every 
{{m_client}} datatable shows on every
customer regardless of what it was registered against.

h3. Steps to reproduce

# {{POST /datatables}} with {{apptableName: "m_client"}} and {{entitySubType: 
"Person"}}.
# {{GET /datatables?apptable=m_client}} -- the JSON response *does* contain 
{{"entitySubType": "Person"}}.
# Generate a client from the published OpenAPI document (any generator).
# The type for the GET response has no {{entitySubType}} member.

h3. Actual

The runtime JSON and the published schema disagree. A generated type cannot 
express a field the endpoint
always returns.

h3. Expected

{{GetDataTablesResponse}} declares {{entitySubType}}, matching both the runtime 
response and the request
DTO that already declares it.

h3. Evidence

All references below are against {{develop}}.

|| Where || What it shows ||
| {{DatatableData}} | declares {{entitySubType}}, takes it in {{create(...)}} 
and assigns it; nothing excludes it from serialisation |
| {{DatatableReadServiceImpl}} lines 72, 93, 96 | list path selects 
{{entity_subtype}} and passes it to {{DatatableData.create(...)}} |
| {{DatatableReadServiceImpl}} lines 106, 119, 123 | single-table path does the 
same |
| {{DatatablesApiResourceSwagger}} line 81 | {{PostDataTablesRequest}} declares 
{{entitySubType}} |
| {{DatatablesApiResourceSwagger.GetDataTablesResponse}} | does not declare it |
| {{DatatablesApiResource}} lines 101, 233 | {{getDatatables}} and 
{{getDatatable}} both name {{GetDataTablesResponse}} as their {{@ApiResponse}} 
schema, so one omission affects both endpoints |

The clearest evidence is in Fineract's own test suite.
{{integration-tests/.../datatable/DatatableIntegrationTest}} imports the 
*generated* client model
{{org.apache.fineract.client.models.GetDataTablesResponse}} and sets 
{{entitySubType}} on eleven separate
datatable creations -- and never once asserts it comes back, because the 
generated model has no getter for
it. {{validateCreateAndEditDatatable}} creates a datatable with 
{{CLIENT_PERSON_SUBTYPE_NAME}} ("Person"),
reads it back with {{getDataTableDetails(...)}}, and can assert on the column 
headers but not on the sub
type it just set.

h3. Proposed fix

One field on {{GetDataTablesResponse}}:

{code:java}
@Schema(example = "Person", description = "The entity sub type the datatable is 
registered against, "
        + "when the application table supports one (for example Person or 
Entity on m_client). "
        + "Null when the registration is not scoped to a sub type.")
public String entitySubType;
{code}

No runtime behaviour changes; the response body is unchanged byte for byte.

h3. Test

{{fineract-client}} is generated from this spec ({{inputSpec = 
file(swaggerFile)}},
{{dependsOn(':fineract-provider:resolve')}}) and {{integration-tests}} depends 
on it, so a client-side
assertion is a real test of this defect rather than a restatement of behaviour 
that already worked. One
line inside the existing {{validateCreateAndEditDatatable}}, after the 
{{getDataTableDetails(...)}} call
that is already there:

{code:java}
assertEquals(CLIENT_PERSON_SUBTYPE_NAME, dataTable.getEntitySubType());
{code}

Verified by generating the Java client both ways: from {{develop}}'s spec the 
model has three getters
({{getApplicationTableName}}, {{getColumnHeaderData}}, 
{{getRegisteredTableName}}); regenerated with the
fix it has four, the new one being {{getEntitySubType()}}. So the assertion 
does not compile before the
change and passes after it.



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

Reply via email to