OpenAPITools / OpenAPITools/openapi-generator
[BUG][Swift] JSON not deserialized if expected type is "just" a string
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)? Yes
- What's the version of OpenAPI Generator used?
master - Have you search for related issues/PRs?
- What's the actual output vs expected output?
Description
I have an API returning JSON (always, the Content-Type on the answer is JSON, the documentation specified JSON, etc.
openapi-generator version
master
OpenAPI declaration file content or url
openapi: 3.0.1
info:
title: Test string API
version: 1.0.0
components:
responses:
OK_200:
description: OK
content:
application/json:
schema:
type: "string"
paths:
/ping:
get:
summary: Endpoint
description: Returns a JSON-encoded string
responses:
'200':
$ref: "#/components/responses/OK_200"
Command line used for generation
generate -i string-api.yaml -g swift4 -o output
Steps to reproduce
- Implement the API and return the following full HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
"API String Response"
- Query the API using the code generated
- The result of the API is
"\"API String Response\""instead of"API String Response"
The JSON is not deserialized. Despite the appropriate Content-Type and documentation.
Related issues/PRs
None I could find.
Suggest a fix
The issue seems to arise from this special case:
https://github.com/OpenAPITools/openapi-generator/blob/master/modules/openapi-generator/src/main/resources/swift4/AlamofireImplementations.mustache#L362-L380
Although I do understand the use case (sometimes, we just want the response's body as string, not interpreted), this is preventing proper use of the code when we have an API returning a simple string.
Obviously changing the API to wrap the value inside an object or an array isn't acceptable (nor always possible if the API isn't under our control).
I would suggest to use the AlamofireRequestBuilder (returned by getNonDecodableBuilder) for this use case. While the AlamofireDecodableRequestBuilder should always try to decode its content.
Moreover, because of https://bugs.swift.org/browse/SR-6163, We won't be able to rely on JSONDecoder for String values (same is true for plain numbers (int/float), boolean and null). In all these cases, we should add a case in the AlamofireDecodableRequestBuilder to use JSONSerialization.jsonObject(with: json, options: .allowFragments)) as? T instead. The existing special case for String should be removed and replaced by this as well.
Note: There might be many issues linked to https://forums.swift.org/t/top-level-t-self-encoded-as-number-json-fragment/11001 as well.
Maybe switching to JSONSerialization with .allowFragments as the JSON Serializer/Deserializer would be a good idea...
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with modules/openapi-generator/src/main/resources/swift4/AlamofireImplementations.mustache around lines 362-380 and reproduce the generated client using the provided OpenAPI declaration and JSON string response. Check how the decodable and non-decodable request builders handle a top-level string. Done means a documented JSON string is deserialized without the extra quotes while the raw-body use case remains available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- openapi, swift
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100