[ 
https://issues.apache.org/jira/browse/FINERACT-2776?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Adam Saghy reassigned FINERACT-2776:
------------------------------------

    Assignee: Farooq Ayoade

> 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
>            Assignee: Farooq Ayoade
>            Priority: Minor
>
> 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