Swagger documentation "try it out" is not working due to CORS problem
background: We have swagger documentation feature that has "try it out" feature. This allows users to try API from the browser.
problem: It is not working, because browser makes a preflight request and it fails with "failed to fetch" or similar error. This is bad UX.
desired behavior: Users can use the "try it out" & "execute" and they get a meaningful response
Solution proposal: It is possible to configure API umbrella so that headers are overwritten. There is an existing REST API that can be called to override the response headers for a particular method via PUT method and we have a wrapper for it.
Story: As a API owner, when the I go to advanced settings* and click "enable CORS support" values are fetched from API backend and prefilled to the text edit box with "x-api-key" as added header value. The text edit field is not visible until I click the "enable CORS support" tickbox. Then I can edit the value and hit save & publish button to set the config to proxy. If i don't understand what I'm doing, I can read descriptive help text explaining what is happening. If I want to disable CORS support, I click the tickbox and save&publish button and text edit field will disappear.
*things will look bit different in the "next" version
Before overriding the Access-control-allow-headers we need to do a OPTIONS method query to the API owner back end and see what values are returned. Then we need to append x-api-key to the "Access-control-allow-headers" list. The API backend server response needs to be checked every time values are changed via APInf. We need to provide a simple toggle "CORS ON/OFF" and additional text field allowing API owner to override the values at will. It may be that API backend is updated and then our of synch with umbrella settings. Additionally, when user enables this, we need to do the following: for all OPTIONS method queries, disable x-api-key requirement. Browser does not understand to set the x-api-key to the request when it does OPTIONS preflight request.
Explanation of the setting is also required: "Set "Access-control-allow-headers" value to enable Swagger documentation "try it out" feature. By enabling this feature API users can try the API from browser instead of terminal or Postman. If you update your backend settings, please remember to update values here by hitting the "Save&publish" button
when user clicks the tickbox ON, following needs to happen:
- Do OPTIONS query to API backend
- check the return value; if Access-control-allow-headers value is returned, proceed, otherwise show an error: "Unable to retrieve Access-control-allow-headers information from API backend. Please check your server settings and try again. + what ever came from the backend
- get the API information If not ok, show error: "Unable to fetch API data from proxy"
- Append "x-api-key" to Access-control-allow-headers list (if present and show in the UI)
when user hits the save & publish:
- save the configuration
when user unticks, following needs to happen:
- hide text field
when user unticks, following needs to happen:
- remove the x-api-key from the
- revert the "disable x-api-key for OPTIONS requests"
- hide text field
If you want to try this with POSTMAN here is an example, pay attention to "sub_settings":
Needed headers: x-admin-auth-token, x-api-key
example body:
{ "api": { "backend_host": "devel3.t5.fi", "backend_protocol": "https", "balance_algorithm": "least_conn", "created_at": "2018-06-20T12:15:20Z", "created_by": "a14d55ab-906b-4769-aa29-e7301bbe20e0", "deleted_at": null, "frontend_host": "nightly.apinf.io:3002", "name": "ilari CORSSAA", "servers": [ { "host": "devel3.t5.fi", "port": 443, "id": "21a71d80-1171-4366-9bb4-866e6a406a38" } ], "settings": { "allowed_ips": null, "allowed_referers": null, "anonymous_rate_limit_behavior": null, "api_key_verification_level": null, "api_key_verification_transition_start_at": null, "append_query_string": null, "authenticated_rate_limit_behavior": null, "disable_api_key": false, "error_data": {}, "error_templates": {}, "http_basic_auth": null, "pass_api_key_header": null, "pass_api_key_query_param": null, "rate_limit_mode": "unlimited", "require_https": null, "require_https_transition_start_at": null, "required_roles": null, "required_roles_override": null, "error_data_yaml_strings": {}, "headers_string": "", "default_response_headers_string": "", "override_response_headers_string": "", "id": "6cd330ae-31c0-43e3-a69a-c9e4499e4283" }, "sort_order": 4840000, "sub_settings": [{ "http_method": "OPTIONS", "regex": ".*", "settings": { "allowed_ips": null, "allowed_referers": null, "anonymous_rate_limit_behavior": "ip_fallback", "api_key_verification_level": null, "api_key_verification_transition_start_at": null, "append_query_string": null, "authenticated_rate_limit_behavior": "all", "disable_api_key": true, "error_data": {}, "error_templates": {}, "http_basic_auth": null, "override_response_headers": [ { "key": "Access-control-allow-headers", "value": "X-Api-Key", "id": "4ffce302-3219-4378-8b9f-ae8b76e3161e" } ], "pass_api_key_header": null, "pass_api_key_query_param": null, "rate_limit_mode": null, "require_https": null, "require_https_transition_start_at": null, "required_roles": null, "required_roles_override": null, "error_data_yaml_strings": {}, "headers_string": "", "default_response_headers_string": "", "override_response_headers_string": "Access-control-allow-headers: X-Api-Key" }
}],
"updated_at": "2018-06-20T12:27:20Z",
"updated_by": "9485bbe9-d41c-434a-a2d2-bd15532d62b5",
"url_matches": [
{
"backend_prefix": "/api/rest/v1/",
"frontend_prefix": "/managementrestapibeta3/",
"id": "54c3f1dc-0085-49ca-ae85-6d14aae99fb9"
}
],
"version": 8,
"id": "6d2711f0-89a4-453d-9476-1bf7bbcc5131",
"creator": {
"username": "[email protected]"
},
"updater": {
"username": "[email protected]"
}
}
}
additional documentation:
https://api-umbrella.readthedocs.io/en/latest/admin/api.html#!/api/put_api_umbrella_v1_apis_id https://medium.com/apinf/said-swagger-ui-browser-i-need-to-cors-what-options-do-i-have-5a9d6aa80ea4
this replaces issues: #2604 #3402 #2696
latest plan is to do global solution with admin off / on switch.
basically we now have swagger support (CORS) in latest umbrella. The status is that we have "undone" the trouble we introduce with umbrella. But if the API owner does not set correct headers (like Access control allow origin) the swagger will not work. Need to determine if we start messing more with the responses, give users options or leave it to the API owner to do and help with documentation