Skip to content

DWAPI Custom Search Swagger doc is innacurate #657

Description

@nunoaguiar

Is your feature request related to a problem? Please describe.

The CustomSearch parameter on GET /dwapi/ecommerce/orders/search is impossible to use correctly from the Swagger UI, because the documentation for its syntax is destroyed by the doc renderer.

The XML doc on OrderSearchRequest.CustomSearch describes the format using <c> tags around tokens containing angle brackets:

/// Format: <c>fieldname&lt;op&gt;value</c> where op is <c>eq</c>, <c>in</c>, or <c>like</c>.
/// For <c>in</c>, pipe-separate multiple values: <c>fieldname&lt;in&gt;val1|val2</c>.
/// Example: <c>OrderCustomerCountryCode&lt;eq&gt;DK;OrderCurrencyCode&lt;in&gt;DKK|EUR</c>

NSwag strips <c> tags without substituting markdown backticks, so /dwapi/api.json ends up containing the operators as bare angle-bracket tokens:

"name": "CustomSearch",
"in": "query",
"description": "One or more field-specific filters, semicolon-separated.\nFormat: fieldname<op>value where op is eq, in, or like.\nFor in, pipe-separate multiple values: fieldname<in>val1|val2.\nExample: OrderCustomerCountryCode<eq>DK;OrderCurrencyCode<in>DKK|EUR"

Swagger UI renders parameter descriptions as Markdown with raw HTML enabled. <op>, <eq> and <in> are therefore parsed as unknown HTML tags and rendered as nothing. What a consumer actually reads on /dwapi/docs is:

One or more field-specific filters, semicolon-separated.
Format: fieldnamevalue where op is eq, in, or like.
For in, pipe-separate multiple values: fieldnameval1|val2.
Example: OrderCustomerCountryCodeDK;OrderCurrencyCodeDKK|EUR

The only visible separator left is the pipe, so the documented syntax reads as field|value. We lost time building &CustomSearch=OrderType|Units and could not work out why it had no effect.

A second problem makes this much worse: invalid CustomSearch input fails silently. FieldSearch.TryParse returns false when no token contains a recognised operator, and OrdersController.BuildSearchFilter simply does not set filter.FieldSearches in that case. Likewise, OrderRepository.GetFieldSearchFilterClause continues past any field name that is not in its whitelist. Either way the endpoint returns HTTP 200 with the full unfiltered result set and no warning. There is no feedback signal telling the caller their filter was discarded, so a wrong syntax is indistinguishable from a filter that legitimately matches everything.

Describe the solution you'd like

  1. Make the syntax survive the renderer. Put literal markdown backticks in the XML doc instead of relying on <c>, so the description in api.json is already markdown-safe and Swagger UI renders the operators inside a code span:

    /// Format: `fieldname&lt;op&gt;value` where op is `eq`, `in`, or `like`.
    /// For `in`, pipe-separate multiple values: `fieldname&lt;in&gt;val1|val2`.
    /// Example: `OrderCustomerCountryCode&lt;eq&gt;DK;OrderCurrencyCode&lt;in&gt;DKK|EUR`
  2. Fail loudly on unusable input. Return 400 Bad Request from GET /dwapi/ecommerce/orders/search when CustomSearch is non-empty but yields no usable filter — either because no token parsed, or because every field named is outside the whitelist. The response body should name the offending token. Silently returning an unfiltered 200 is the single biggest reason this took as long as it did to diagnose.

  3. Optionally, document which field names are accepted (the GetFieldSearchFilterClause whitelist plus everything from Services.OrderFields.GetOrderFields()), since that is currently only discoverable by reading the source.

Additional context

Files involved:

  • Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrderSearchRequest.cs — the XML doc on CustomSearch
  • Dynamicweb.Frontend.Classic.Api.Ecommerce/Controllers/OrdersController.csBuildSearchFilter, where a failed parse is dropped
  • src/Features/Ecommerce/Dynamicweb.Ecommerce/Orders/FieldSearch.csTryParse, same rendering issue in its <remarks>
  • src/Features/Ecommerce/Dynamicweb.Ecommerce/Orders/OrderRepository.csGetFieldSearchFilterClause, where a non-whitelisted field is skipped

Steps to reproduce the documentation defect:

  1. Open /dwapi/docs, expand GET /dwapi/ecommerce/orders/search, and read the CustomSearch description — the operators are absent.
  2. Fetch /dwapi/api.json and search for "name": "CustomSearch" — the operators are present as bare <op> / <eq> / <in>, confirming the loss happens at render time, not generation time.

Steps to reproduce the silent-failure behaviour, against a solution with a custom order field OrderType:

# discarded filter, returns 200 and every order
curl -H "Authorization: Bearer $TOKEN" \
  "https://<host>/dwapi/ecommerce/orders/search?CustomSearch=OrderType|UNIT"

# working filter
curl -H "Authorization: Bearer $TOKEN" \
  "https://<host>/dwapi/ecommerce/orders/search?CustomSearch=OrderType%3Ceq%3EUNIT"

Both return 200 OK; only the second one filters.

Scope check: we walked every description in a generated api.json looking for bare HTML-like tokens and found three. The other two — ManufacturerViewModel.logo (<img>) and BomGroupViewModel.noneSelectedText (<option>) — are cosmetic, since the surrounding prose still makes sense without them. CustomSearch is the only one where the lost text is the specification.

Best Regards
Nuno Aguiar

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions