swagger-ui: Large response bodies cause hanging
| Q | A | 
|---|---|
| Bug or feature request? | Bug | 
| Which Swagger/OpenAPI version? | 2.0 | 
| Which Swagger-UI version? | 3.4.0 | 
| How did you install Swagger-UI? | local dev server | 
| Which browser & version? | Chrome 61 | 
| Which operating system? | macOS High Sierra | 
Demonstration API definition
Swagger 2 Petstore is sufficient.
Configuration (browser query string, constructor, config.yaml)
Default.
Current Behavior
As an example, GET /pet/findByStatus in the Petstore currently returns 1.8MB of JSON when all statuses are selected. This is a pretty big chunk of data, but Swagger-UI insists on rendering the entire body, which is neither performant or useful. The main thread of the application is locked for upwards of 20 seconds on my machine.
Possible Solution
Truncate or refuse to display large textual response bodies.
Context
GET /pet/findByStatus is my favorite operation to use when testing UI enums, so this is something that impedes me pretty regularly.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 27
- Comments: 91 (37 by maintainers)
Ran into this recently too. Looks like you can turn it off via config. For me, this worked:
Yes, just check the releases page: https://github.com/swagger-api/swagger-ui/releases
This issues is not high priority, most developers do not have API with large responses and when large data is needed pagination helps reduce the amount of data retrieved at once
2,3 megabytes are slowing down the browser. I don’t think this is huge amount of data
The issue doesn’t seem to be caused by response size, but the number of records. I have a result with only 2 columns (int, date) but result sets >1000 records cause the UI to be awful, even though the total response is < 1mb. The same call with Postman renders in about a second.
Since swagger UI is only for demonstrating how to use the API, I’d like an easy way to set a max number of rendered records in swagger. Is that possible?
@Kraego, @BjoernHund as mentioned above, you can speedup rendering by disabling syntax highlight. Here is example for AspNetCore.
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.2" />Configuration
I’d like to tag on to this issue. I’ve been using Swashbuckle.AspNetCore 5.5.1 (Swagger-UI v3.26.0 I believe) and have a somewhat large response body (20k lines of json give or take). In the 5.5.1, the request duration takes 45ms and displays almost instantly. Using the exact same configuration with 5.6.0 (Swagger-UI v.3.32.5), request duration takes 45ms and locks the interface 30 seconds and finally displays. Once that is rendered, if I minimize or expand anything else, the interface is locked again for 30 seconds each time. Once I clear the results, the interface speed returns to normal.
The coloring added is fantastic but I am currently stuck using the older version as the speed is simply too much of an issue.
Thanks for the hint on where to start, @heldersepu! I have implemented two new config options to allow for:
I have at fix
Do something like this in your webservice method
I.e. set the Content-Disposition header to something containg attachment
If you look at https://github.com/swagger-api/swagger-ui/blob/master/src/core/components/response-body.jsx#L61 you will see that swagger UI checks if the HTTP header “Content-Disposition” contains the string “attachment” If it does, the content is NOT shown directly, but hidden behind a download link. Note that response-body.jsx does NOT check anything about the well-formedness of the content disposition header. It just checks if it contains the word “attachment”. For this reason I just dumped some extra field
swaggerDownload="attachment";, in order to have the word “attachment” there, without confusing other systems.If this API method is invoked normally from a browser, rather than from swagger UI, it would just render the content inline, as this is specified, and also the default behaivour if Content-Disposition is not specified
cc @webron, would appreciate a priority assignment
Wish this could be automated if payload > x MB or something.
Remember the project is open source, if this is a big issue to you the code is there for you to fix it
a quick fix could be not to display such a large responses, instead show something like github does on diff:
Large diffs are not rendered by default.or truncate the body to 20000:
If we truncate the response will show:
can't parse JSON. Raw result:100x 👍
Another alternative for those that want to see this resolved and don’t like any of the existing workarounds, also don’t want to spend the time troubleshooting and debugging this, consider hiring someone
Alternatively, if you don’t have time to contribute but want this to work with large payloads, simply use the workaround posted in the previous comment from September 2000. I continue to use this workaround for older APIs I don’t have time to rework and paginate.
Setting
content-typetoapplication/octet-stream, as well ascontent-dispositiontoattachmentwill force the swagger to display “Download file” link instead of rendering the contents.I may take a look at this, as the problem is an issue for me now. But for those who want to dig into this one, this will most likely be an issue with string concatenation in the body rendering. This usually involves the expensive process of allocating memory many times if done the wrong way (e.g. just using stringc = stringa + stringb repeatedly). I have seen this kind of issue several times in the past. Instead build a array of strings and then concatenate it.
We have the same problem. The swagger ui does not respond.
I am using swagger with NodeJS and one of API response size is
1.54MBnot working with me and also hanginghighly depends on the use case.
anyway it’s not implemented that way in postman for no reason, expensive operations should not block UI, talking about bad practices.
in latest builds it doesn’t even take a really “large” result for swagger-ui to begin stalling.
Hi everybody,
Let me first address the current state of this issue. Where we are and where we want to get.
Large response bodies are indeed causing issues. The issue with large response bodies starts with Immutable serialization into redux store and continues with rendering with or without syntax highlighting.
We will address this problems progressively in multiple steps.
Step 1
Give ability to disable syntax highlighting. As mentioned multiple times in this issue, syntax highlighting can be disabled fully by utilizing
syntaxHighlight.activated=falseoption. This is already fully supported.Step 2
Detect possible large response bodies and disable syntax highlighting for them even when
syntaxHighlight.activated=true. There is a PR that actually comes pretty close to our idea: https://github.com/swagger-api/swagger-ui/pull/9625Step 3
Detect possible large response bodies and disable rendering for them, but provide ability to download. This way we’ll avoid any possible operation performed on large respose bodies expect storing it in redux store. We still have to provide ability to download the large response body though. Again https://github.com/swagger-api/swagger-ui/pull/9625 comes pretty close to our idea.
Entire syntax highlighting feature has been consolidated into single
syntax-highlightingplugin in https://github.com/swagger-api/swagger-ui/pull/9783. This makes it possible to completely override how syntax highlighting is done or switch the syntax highlighter entirely. We opted to usehighlight.jsfor default syntax highlighter as it’s more performant thanprism.@nojaf,
Thank you for your PR, be we will not be incorporating your changes into the core SwaggerUI. We already use custom build MonacoEditor in SwaggerEditor@5. We have to be very careful what dependencies we pull into our bundles and how they affect each other. Using MonacoEditor is a major arch decision, we’ll rather provide progressive enhancement to this issue as described in previous steps.
The https://github.com/swagger-api/swagger-ui/pull/9783 opened possibility to utilize custom syntax highlighting mechanism, and I’ve seen you’ve already transformed your PR into the plugin that other people can utilize if they choose to.
@heldersepu,
This particular definition according to my research, suffers with different issues not related to large response bodies. When expanding operation most time is spent in
dereferencing(resolution) and JSON Schema sample generation. Only after that (when browser still hasn’t crashed) the syntax highliting issue comes into light.No, it makes more sense to find out if the maintainers would ever consider merging it before I spent my time creating the PR.
The Monaco editor can be tweaked to appear very minimal (readonly mode, remove line numbers, side bar, …)
Hello,
We are also experiencing this issue. After investigating, I’ve found that
react-syntax-highlighterseems to be the primary cause of the bottleneck:Is there any possibility of replacing this component? I conducted a preliminary test by swapping it out for
@monaco-editor/reactand immediately observed significantly improved performance with large results.I’m ready to submit a pull request if the maintainers are open to this change.
Hi everyone, just letting you know I’m investigating this issue and testing this PR proposing a fix with a specification from this issue.
Unfortunately, it seems like only adding this render limit is not enough. You can check it out with these steps (using https://github.com/swagger-api/swagger-ui/pull/9625):
CRUD - AGM Disease AnnotationsI also tried adding the limit to other components, ex.
RequestBodyEditor,Curl, but it hasn’t fixed the crash when going through the mentioned steps.The memory usage is still high when just expanding the operation, and even when disabling rendering for some of the components (
RequestBody,Response). I think that the issue might partially lie with immutable types, at least from checking the memory usage. I will be investigating this further.… my 2cents
Remember this is a free and open source project, the fastest way to get something done is to do it yourself … that is what I did when I was using swagger often, if there was something that really bothered me I would spend the time to get familiar with the code and send a PR with a fix or workaround
Now specifically to this issue, I run into this only in theory, I never had a production API with this issue any large responses should have pagination to reduce exactly this issue as other consumers will run into this same issue
When it will FIXED ? In 10 years ?
The disabling syntax highlighting workaround didn’t work for me, so I kept exploring. I couldn’t possibly think what was causing it to hang so badly, as my controller method and associated data structures weren’t particularly chunky. Then I realised that I’m declaring in an attribute that my method will be returning a
BadHttpRequestExceptionin cases where I’m doing validation on the request data (this is in ASP.NET Core by the way):When seeing that the Swagger UI generates an example instance of this return type, this results in an enormous amount of JSON as Swagger populates every possible property recursively, which is what’s causing the hanging in every single interaction in my case:
Removing my usage of this attribute to declare this possible return type is what made the UI responsive for me again. This is obviously a workaround and not a solution, but I thought I’d share my findings here in case it helps other folk stop tearing their hair out!
Edit: It’s just occurred to me that I shouldn’t actually be throwing exceptions anyway, I should be returning
BadRequestObjectResultimplicitly by calling theBadRequest("My error message...")helper, and just stating that the action can return 400s with[ProducesResponseType((int)HttpStatusCode.BadRequest)]without stating a type! But the issue could still manifest for someone else if they declare an expected result type that has a potentially very deep tree structure.The workaround for those that use Spring (in application.yml):
your argument makes no sense to me. if there’s no purpose (in showing the content), why would you download it to eventually do exactly that.
download is okay, it would resolve the most important aspect of this issue. but it’s still less convenient.
btw this issue got much worse in recent versions, presumably due to pretty-print / color enhancements which make rendering even more expensive.
why not render asynchronously in stages, like eg. postman does. it works well and there’s barely any need for switches or limits.