|
| 1 | +# OpenAPI |
| 2 | + |
| 3 | +The OpenAPI import feature was failing when trying to import specifications from URLs like https://catfact.ninja/docs?api-docs.json. The error "The fetched content does not look like a valid OpenAPI spec (JSON or YAML)" was shown even though the content was a valid OpenAPI 3.0 specification. This was caused by a bug in the openapi_spec package (v0.15.0) that cannot parse OpenAPI specs containing "security": [[]] (empty security arrays), which is valid according to the OpenAPI 3.0 specification. |
| 4 | + |
| 5 | +> Fix |
| 6 | +
|
| 7 | +Added a workaround in OpenApiImportService.tryParseSpec() that detects parsing failures and automatically removes problematic security fields containing empty arrays before retrying the parse operation. This is a temporary workaround until the upstream package is fixed. |
| 8 | + |
| 9 | +- [APIDash](https://drive.google.com/file/d/1CWocxCVW99-bEWkZlwInGq0JykHalv9a/view?usp=sharing) - Works without any fix |
| 10 | +- [Cat Fact API](https://drive.google.com/file/d/1ox71b3tT4Lv-9jw7zV1ronWQR_uW3K25/view?usp=drive_link) - Works with this fix |
| 11 | +- [DigitalOcean Droplet Metadata API](https://drive.google.com/file/d/1XKZXJvrwvAVm3OVBEZFhScOuCMjPJBZh/view?usp=drive_link) - Works without any fix |
| 12 | +- [GitHub v3 REST API](https://drive.google.com/file/d/1WcJXSosHPD0uiybJrqpJSknM5FA0De02/view?usp=drive_link) - Doesn't Work |
| 13 | +- [Swagger Petstore](https://drive.google.com/file/d/1LBqBrlcsXo7Clr7VKn7CYe75c_H4U8zQ/view?usp=drive_link) - Doesn't Work |
| 14 | +- [RailwayStations REST API](https://drive.google.com/file/d/1jVFk-hNf_gb_VeBuAomOgh6tWByU9Fyi/view?usp=drive_link) - Doesn't Work |
| 15 | +- [UniProt REST API Server](https://drive.google.com/file/d/1KTIqKC7SludxsyCYN6kXWQySve4GpbhD/view?usp=drive_link) - Doesn't Work |
| 16 | +- [VIT-AP VTOP API](https://drive.google.com/file/d/1B5Mh3IK2uUBoRSocEKQd2Dvf7SZWm03M/view?usp=drive_link) - Works without any fix |
| 17 | + |
| 18 | +It’s not our parser that causes the issue. The failures come from the documents themselves and how the openapi_spec package (correctly) enforces OpenAPI shapes. Valid security fields work fine as per the package docs; the broken cases are due to invalid spec content. |
| 19 | + |
| 20 | +### Findings per document |
| 21 | + |
| 22 | +- cat_facts.json (also the Cat Facts URL) |
| 23 | + |
| 24 | + - Problem: Top-level security is malformed: security: [[]] |
| 25 | + - Why it fails: In OpenAPI 3.0, top-level security must be an array of SecurityRequirement objects (maps). Examples: |
| 26 | + - Valid: security: [] (no requirements) or security: [ { api_key: [] } ] |
| 27 | + - Invalid: security: [[]] (array of arrays) |
| 28 | + - openapi_spec error: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>' |
| 29 | + - Conclusion: The document is invalid. This is not a general “security field” issue, just this malformed shape. |
| 30 | + |
| 31 | +- railway-stations.yaml |
| 32 | + |
| 33 | + - Problem: Component parameter reference points to a Parameter missing required fields (e.g., 'in'). |
| 34 | + - Error: CheckedFromJsonException: Could not create Parameter. There is a problem with "in". Invalid union type "null"! |
| 35 | + - The stack/message points at $ref: #/components/parameters/Authorization. |
| 36 | + - Conclusion: Not related to security. The referenced Parameter definition is incomplete (missing in: header|query|path|cookie) or otherwise invalid. |
| 37 | + |
| 38 | +- travel.yaml |
| 39 | + |
| 40 | + - Problem: Same class of failure as railway-stations.yaml, with a parameter ref like $ref: #/components/parameters/page. |
| 41 | + - Error: CheckedFromJsonException... problem with "in" (Invalid union type "null"). |
| 42 | + - Note: components.securitySchemes is present here and is not the cause. |
| 43 | + - Conclusion: Also a spec issue with parameter component definitions/references. |
| 44 | + |
| 45 | +- digitalocean.yaml |
| 46 | + - Result: Parses successfully with openapi_spec. |
| 47 | + - Note: No top-level security; nothing problematic here. |
| 48 | + - Conclusion: Confirms the parser handles valid documents correctly. |
| 49 | + |
| 50 | +Steps to reproduce failures from local files, |
| 51 | + |
| 52 | +``` |
| 53 | +import 'dart:io'; |
| 54 | +import 'package:openapi_spec/openapi_spec.dart'; |
| 55 | +
|
| 56 | +void main(List<String> args) async { |
| 57 | +
|
| 58 | + // Pass file paths as args below. |
| 59 | + final paths = args.isNotEmpty |
| 60 | + ? args |
| 61 | + : <String>[ |
| 62 | + './cat_facts.json', |
| 63 | + './railway-stations.yaml', |
| 64 | + ]; |
| 65 | +
|
| 66 | + for (final p in paths) { |
| 67 | + stdout.writeln('\n=== Parsing: $p ==='); |
| 68 | + final f = File(p); |
| 69 | + if (!await f.exists()) { |
| 70 | + stdout.writeln('Skip: file not found'); |
| 71 | + continue; |
| 72 | + } |
| 73 | +
|
| 74 | + final content = await f.readAsString(); |
| 75 | +
|
| 76 | + try { |
| 77 | + final spec = OpenApi.fromString(source: content, format: null); |
| 78 | + stdout.writeln('SUCCESS: title="${spec.info.title}", version="${spec.info.version}"'); |
| 79 | + stdout.writeln('Paths: ${spec.paths?.length ?? 0}'); |
| 80 | + } catch (e, st) { |
| 81 | + final err = e.toString(); |
| 82 | + stdout.writeln('FAIL: ${err.substring(0, err.length.clamp(0, 400))}...'); |
| 83 | + // Stack Trace |
| 84 | + final stStr = st.toString(); |
| 85 | + if (stStr.isNotEmpty) { |
| 86 | + stdout.writeln('Stack:\n$stStr'); |
| 87 | + } |
| 88 | + } |
| 89 | + } |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +### How to run |
| 94 | + |
| 95 | +- Create a new dart project, put the openapi spec file and this script there. |
| 96 | +- Add the depndency, `dart pub add openapi_spec: ^0.15.0` |
| 97 | +- Run: |
| 98 | + - `dart run path/to/this/file` |
| 99 | + |
| 100 | +### Expected outcomes |
| 101 | + |
| 102 | +- `cat_facts.json` |
| 103 | + |
| 104 | + - FAIL with an error like: |
| 105 | + - type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>' |
| 106 | + - This is triggered by the invalid top-level security shape: security: [[]] |
| 107 | + |
| 108 | +- `railway-stations.yaml` |
| 109 | + - FAIL with an error like: |
| 110 | + - CheckedFromJsonException: Could not create `Parameter`. There is a problem with "in". Invalid union type "null"! |
| 111 | + - This points to a components/parameters reference missing required “in”. |
0 commit comments