Open pavelkornev opened 10 months ago
Am also experiencing the same, Any fix/walk-around ?
UPDATE: 13th Feb 2024
Walk-around is to downgrade to v7.1.0
I can confirm. This is very reproducible.
Investigating this issue within Swagger Client, I found out that the resolve mechanism executes for a long time due to the complexity of the specification with the nested references. The specification should eventually be resolved but the operations take too long. Because of this SwaggerUI will freeze.
I tried breaking out of the traversal early by creating and setting a maximum count of it to a 1000 for each run of the plugins. I broke out of the execution here https://github.com/swagger-api/swagger-js/blob/f00b527fd71f46ccf1a4ae14853edc5452160b04/src/specmap/index.js#L108 and here https://github.com/swagger-api/swagger-js/blob/f00b527fd71f46ccf1a4ae14853edc5452160b04/src/specmap/index.js#L137 if the limit was reached. This allowed the specification to be partially resolved and loaded in SwaggerUI, although rendering slowly. Unfortunately, as we don’t resolve everything, components looked like this:
The missing values are unresolved, for example scenario
from the second image is:
{
allOf: [
{
'$ref': '#/components/schemas/com.sap.ctsm.backend.core.api.study.v1.StudyAPIv1.Scenarios-create'
}
],
nullable: true
}
and kitTypeAssignments
:
{
type: 'array',
items: {
'$ref': '#/components/schemas/com.sap.ctsm.backend.core.api.study.v1.StudyAPIv1.KitTypeTreatmentAssignments-create'
}
}
Perhaps we could render these unresolved definitions with reference strings but resolving everything is not possible at the moment.
The crashing issue was addressed in https://github.com/swagger-api/swagger-js/pull/3380, released as https://github.com/swagger-api/swagger-js/releases/tag/v3.25.3.
As it turned out, the complex specification was being eventually resolved, but the operations took too long due to the nested definitions. To fix this, we limited the maximum traversal depth for each run of the plugins. This allows us to get a partially resolved specification, which has to be resolved further in Swagger UI. A fix was also added for the limit of the plugins dispatch runs, which now correctly tracks each plugin separately.
Rendering schemas not resolved by Swagger Client addressed in https://github.com/swagger-api/swagger-ui/pull/9629.
This still fails on the original example given in the issue description.
Steps:
Please reopen the issue!
Hi @pavelkornev,
There are number of issues that SwaggerUI is having with https://api.sap.com/odata/1.0/catalog.svc/APIContent.APIs('SAP_ICSM_StudyService')/$value?type=json
The original definition is almost 2MB in size. This alone makes it challenging for SwaggerUI to deal with it.
The complexity of this definition is extreme. By complexity I mean how Schema Objects are referenced and used. SwaggerUI uses SwaggerClient to dereference the definition in a special way - it tries to eliminate all the cycles (circular references) so that SwaggerUI can expect that no cycles are present when rendering.
To eliminate cycles, we use SwaggerClient legacy mechanism for OpenAPI 2.0 and 3.0.x. We use ApiDOM for OpenAPI 3.1.0. Given that you definition is in OpenAPI 3.0.x, SwaggerClient uses legacy mechanism which cannot cope with tracking the references on such a complex definition; we've addressed that in https://github.com/swagger-api/swagger-ui/commit/7300e6c04ec9248f0d7c5c4e0674572847fcd213 where we stop the dereferencing at some point in forced way.
Now ApiDOM can correctly dereference your definition and eliminate all cycles, but it takes around 25 seconds to do so (because of the definition complexity). Without the cycle detection (circular=ignore), ApiDOM can dereference the definition under 1 second.
ApiDOM in future will take over all the dereferencing in SwaggerClient, so it needs to utilize a solution similiar in https://github.com/swagger-api/swagger-ui/commit/7300e6c04ec9248f0d7c5c4e0674572847fcd213. In ApiDOM it's possible to interrupt the traversal in safe way without exposing the incompletely dereferenced definition for cycle occurence.
SwaggerUI unfortunately uses Immutable.js for it's redux store. This means that every piece of JavaScript data that hits the redux store (and state respectively) needs to be serialized into immutable structure and then when it hits the component is (somethimes) deserialized againt to JavaScript value.
Now when you click on to expand the operation, all it's data get dereferenced (+ cycle elimination) which creates extremely large data in browser memory. This data needs to be then serialized into immutable structure. And this is where the browser crash happens - trying to serialize the deferenced operation into redux store.
Even when we would factor our the immutable from the equation, we still need to generate example values for your JSON schemas. That would be slow as well, again given the definition complexity.
This is just analysis of what is currently causing the performance issue on this definition (and others with similiar complexity). It's not one thing, it's a combination of multiple issues.
I've did additional measurements about Immutable.js serialization speed and memory footprint on this definition. I've used Node.js a following APIs for the measurement:
node:perf_hooks
performance.now()
Memory consumption:
Before: 88,788,992 bytes (approximately 88.79 MB)
After: 155,521,024 bytes (approximately 155.52 MB)
Change: Increased by 66.73 MB
Serialization time:
0 ms
Memory consumption:
Before: 90,148,864 bytes (approximately 90.15 MB)
After: 1,044,697,088 bytes (approximately 1.04 GB)
Change: Increased by approximately 954.55 MB
Serialization time:
3163 ms
@char0n would you consider dropping Immutable.js if it causes such a big memory consumption?
@char0n would you consider dropping Immutable.js if it causes such a big memory consumption?
Yes it's a long term plan. But it basically means rewriting the entire SwaggerUI. SwaggerUI basically consists of selectors, reducers, actions and components and Immutable.js is the interface that all of these bind to.
After we've removed Immutable.js we still have problem of dereferencing lasting 25 seconds on your definition. We can solve that by hard stopping the dereferencing at certain level.
Then the next issue is probably going to be example generation from JSON Schemas. Given the extreme schema complexity, this problem can be totally avoided by defining one of the JSON Schema keywords: default
, example
, examples
in all your JSON Schemas.
Q&A (please complete the following information)
Content & configuration
When rendering a complex OpenAPI document, UI comes unresponsive first with the following browser dialog, and eventually crashes later:
Example Swagger/OpenAPI definition: https://api.sap.com/odata/1.0/catalog.svc/APIContent.APIs('SAP_ICSM_StudyService')/$value?type=json
Describe the bug you're encountering
To reproduce...
Steps to reproduce the behavior:
Expected behavior
UI doesn't crash.