Skip to content

Commit

Permalink
fix some UnionAPIModel marshalling issues (#61)
Browse files Browse the repository at this point in the history
Fixes some data marshalling and unmarshalling issues with UnionAPIModel (oneof and anyof).
Also added more tests around it.
  • Loading branch information
tanmaykm authored Sep 9, 2023
1 parent ca99f1d commit c563a12
Show file tree
Hide file tree
Showing 31 changed files with 789 additions and 6 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ keywords = ["Swagger", "OpenAPI", "REST"]
license = "MIT"
desc = "OpenAPI server and client helper for Julia"
authors = ["JuliaHub Inc."]
version = "0.1.17"
version = "0.1.18"

[deps]
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
Expand Down
1 change: 1 addition & 0 deletions src/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ convert(::Type{T}, v::Nothing) where {T<:APIModel} = T()
convert(::Type{T}, v::T) where {T<:OneOfAPIModel} = v
convert(::Type{T}, json::Dict{String,Any}) where {T<:OneOfAPIModel} = from_json(T, json)
convert(::Type{T}, v) where {T<:OneOfAPIModel} = T(v)
convert(::Type{T}, v::String) where {T<:OneOfAPIModel} = T(v)
convert(::Type{T}, v::T) where {T<:AnyOfAPIModel} = v
convert(::Type{T}, json::Dict{String,Any}) where {T<:AnyOfAPIModel} = from_json(T, json)
convert(::Type{T}, v) where {T<:AnyOfAPIModel} = T(v)
Expand Down
26 changes: 23 additions & 3 deletions src/json.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ function iterate(w::JSONWrapper, state...)
end

lower(o::T) where {T<:APIModel} = JSONWrapper(o)
lower(o::T) where {T<:UnionAPIModel} = typeof(o.value) <: APIModel ? JSONWrapper(o.value) : to_json(o.value)
function lower(o::T) where {T<:UnionAPIModel}
if typeof(o.value) <: APIModel
return JSONWrapper(o.value)
elseif typeof(o.value) <: Union{String,Real}
return o.value
else
return to_json(o.value)
end
end

to_json(o) = JSON.json(o)

Expand All @@ -38,6 +46,12 @@ function from_json(o::T, json::Dict{String,Any}) where {T <: UnionAPIModel}
return from_json(o, :value, json)
end

from_json(::Type{T}, val::Union{String,Real}) where {T <: UnionAPIModel} = T(val)
function from_json(o::T, val::Union{String,Real}) where {T <: UnionAPIModel}
o.value = val
return o
end

function from_json(o::T, json::Dict{String,Any}) where {T <: APIModel}
jsonkeys = [Symbol(k) for k in keys(json)]
for name in intersect(propertynames(o), jsonkeys)
Expand All @@ -54,7 +68,7 @@ function from_json(o::T, name::Symbol, json::Dict{String,Any}) where {T <: APIMo
end

function from_json(o::T, name::Symbol, v) where {T <: APIModel}
ftype = property_type(T, name)
ftype = (T <: UnionAPIModel) ? property_type(T, name, Dict{String,Any}()) : property_type(T, name)
if ftype === Any
setfield!(o, name, v)
elseif ZonedDateTime <: ftype
Expand Down Expand Up @@ -89,7 +103,13 @@ function from_json(o::T, name::Symbol, v::Vector) where {T <: APIModel}
setfield!(o, name, map(str2date, v))
else
if (vtype <: Vector) && (veltype <: OpenAPI.UnionAPIModel)
setfield!(o, name, map(veltype, v))
vec = veltype[]
for vecelem in v
push!(vec, from_json(veltype(), :value, vecelem))
end
setfield!(o, name, vec)
elseif (vtype <: Vector) && (veltype <: OpenAPI.APIModel)
setfield!(o, name, map(x->convert(veltype,x), v))
elseif (vtype <: Vector) && (veltype <: String)
# ensure that elements are converted to String
# convert is to do the translation to Union{Nothing,String} when necessary
Expand Down
6 changes: 6 additions & 0 deletions test/client/allany/AllAnyClient/.openapi-generator/FILES
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
README.md
docs/AnyOfBaseType.md
docs/AnyOfMappedPets.md
docs/AnyOfPets.md
docs/Cat.md
docs/DefaultApi.md
docs/Dog.md
docs/OneOfBaseType.md
docs/OneOfMappedPets.md
docs/OneOfPets.md
docs/Pet.md
docs/TypeWithAllArrayTypes.md
src/AllAnyClient.jl
src/apis/api_DefaultApi.jl
src/modelincludes.jl
src/models/model_AnyOfBaseType.jl
src/models/model_AnyOfMappedPets.jl
src/models/model_AnyOfPets.jl
src/models/model_Cat.jl
src/models/model_Dog.jl
src/models/model_OneOfBaseType.jl
src/models/model_OneOfMappedPets.jl
src/models/model_OneOfPets.jl
src/models/model_Pet.jl
src/models/model_TypeWithAllArrayTypes.jl
2 changes: 1 addition & 1 deletion test/client/allany/AllAnyClient/.openapi-generator/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7.0.0-SNAPSHOT
7.0.1-SNAPSHOT
6 changes: 6 additions & 0 deletions test/client/allany/AllAnyClient/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@ Documentation is also embedded in Julia which can be used with a Julia specific

Class | Method
------------ | -------------
*DefaultApi* | [**echo_anyof_base_type_post**](docs/DefaultApi.md#echo_anyof_base_type_post)<br/>**POST** /echo_anyof_base_type<br/>
*DefaultApi* | [**echo_anyof_mapped_pets_post**](docs/DefaultApi.md#echo_anyof_mapped_pets_post)<br/>**POST** /echo_anyof_mapped_pets<br/>
*DefaultApi* | [**echo_anyof_pets_post**](docs/DefaultApi.md#echo_anyof_pets_post)<br/>**POST** /echo_anyof_pets<br/>
*DefaultApi* | [**echo_arrays_post**](docs/DefaultApi.md#echo_arrays_post)<br/>**POST** /echo_arrays<br/>
*DefaultApi* | [**echo_oneof_base_type_post**](docs/DefaultApi.md#echo_oneof_base_type_post)<br/>**POST** /echo_oneof_base_type<br/>
*DefaultApi* | [**echo_oneof_mapped_pets_post**](docs/DefaultApi.md#echo_oneof_mapped_pets_post)<br/>**POST** /echo_oneof_mapped_pets<br/>
*DefaultApi* | [**echo_oneof_pets_post**](docs/DefaultApi.md#echo_oneof_pets_post)<br/>**POST** /echo_oneof_pets<br/>


## Models

- [AnyOfBaseType](docs/AnyOfBaseType.md)
- [AnyOfMappedPets](docs/AnyOfMappedPets.md)
- [AnyOfPets](docs/AnyOfPets.md)
- [Cat](docs/Cat.md)
- [Dog](docs/Dog.md)
- [OneOfBaseType](docs/OneOfBaseType.md)
- [OneOfMappedPets](docs/OneOfMappedPets.md)
- [OneOfPets](docs/OneOfPets.md)
- [Pet](docs/Pet.md)
- [TypeWithAllArrayTypes](docs/TypeWithAllArrayTypes.md)


<a id="authorization"></a>
Expand Down
16 changes: 16 additions & 0 deletions test/client/allany/AllAnyClient/docs/AnyOfBaseType.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# AnyOfBaseType



## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**value** | This is a anyOf model. The value must be any of the following types: Float64, String | | [optional]





[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md)


87 changes: 87 additions & 0 deletions test/client/allany/AllAnyClient/docs/DefaultApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,43 @@ All URIs are relative to *http://localhost*

Method | HTTP request | Description
------------- | ------------- | -------------
[**echo_anyof_base_type_post**](DefaultApi.md#echo_anyof_base_type_post) | **POST** /echo_anyof_base_type |
[**echo_anyof_mapped_pets_post**](DefaultApi.md#echo_anyof_mapped_pets_post) | **POST** /echo_anyof_mapped_pets |
[**echo_anyof_pets_post**](DefaultApi.md#echo_anyof_pets_post) | **POST** /echo_anyof_pets |
[**echo_arrays_post**](DefaultApi.md#echo_arrays_post) | **POST** /echo_arrays |
[**echo_oneof_base_type_post**](DefaultApi.md#echo_oneof_base_type_post) | **POST** /echo_oneof_base_type |
[**echo_oneof_mapped_pets_post**](DefaultApi.md#echo_oneof_mapped_pets_post) | **POST** /echo_oneof_mapped_pets |
[**echo_oneof_pets_post**](DefaultApi.md#echo_oneof_pets_post) | **POST** /echo_oneof_pets |


# **echo_anyof_base_type_post**
> echo_anyof_base_type_post(_api::DefaultApi, any_of_base_type::AnyOfBaseType; _mediaType=nothing) -> AnyOfBaseType, OpenAPI.Clients.ApiResponse <br/>
> echo_anyof_base_type_post(_api::DefaultApi, response_stream::Channel, any_of_base_type::AnyOfBaseType; _mediaType=nothing) -> Channel{ AnyOfBaseType }, OpenAPI.Clients.ApiResponse


### Required Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**_api** | **DefaultApi** | API context |
**any_of_base_type** | [**AnyOfBaseType**](AnyOfBaseType.md)| |

### Return type

[**AnyOfBaseType**](AnyOfBaseType.md)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: application/json
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)

# **echo_anyof_mapped_pets_post**
> echo_anyof_mapped_pets_post(_api::DefaultApi, any_of_mapped_pets::AnyOfMappedPets; _mediaType=nothing) -> AnyOfMappedPets, OpenAPI.Clients.ApiResponse <br/>
> echo_anyof_mapped_pets_post(_api::DefaultApi, response_stream::Channel, any_of_mapped_pets::AnyOfMappedPets; _mediaType=nothing) -> Channel{ AnyOfMappedPets }, OpenAPI.Clients.ApiResponse
Expand Down Expand Up @@ -66,6 +97,62 @@ No authorization required

[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)

# **echo_arrays_post**
> echo_arrays_post(_api::DefaultApi, type_with_all_array_types::TypeWithAllArrayTypes; _mediaType=nothing) -> TypeWithAllArrayTypes, OpenAPI.Clients.ApiResponse <br/>
> echo_arrays_post(_api::DefaultApi, response_stream::Channel, type_with_all_array_types::TypeWithAllArrayTypes; _mediaType=nothing) -> Channel{ TypeWithAllArrayTypes }, OpenAPI.Clients.ApiResponse


### Required Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**_api** | **DefaultApi** | API context |
**type_with_all_array_types** | [**TypeWithAllArrayTypes**](TypeWithAllArrayTypes.md)| |

### Return type

[**TypeWithAllArrayTypes**](TypeWithAllArrayTypes.md)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: application/json
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)

# **echo_oneof_base_type_post**
> echo_oneof_base_type_post(_api::DefaultApi, one_of_base_type::OneOfBaseType; _mediaType=nothing) -> OneOfBaseType, OpenAPI.Clients.ApiResponse <br/>
> echo_oneof_base_type_post(_api::DefaultApi, response_stream::Channel, one_of_base_type::OneOfBaseType; _mediaType=nothing) -> Channel{ OneOfBaseType }, OpenAPI.Clients.ApiResponse


### Required Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**_api** | **DefaultApi** | API context |
**one_of_base_type** | [**OneOfBaseType**](OneOfBaseType.md)| |

### Return type

[**OneOfBaseType**](OneOfBaseType.md)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: application/json
- **Accept**: application/json

[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md)

# **echo_oneof_mapped_pets_post**
> echo_oneof_mapped_pets_post(_api::DefaultApi, one_of_mapped_pets::OneOfMappedPets; _mediaType=nothing) -> OneOfMappedPets, OpenAPI.Clients.ApiResponse <br/>
> echo_oneof_mapped_pets_post(_api::DefaultApi, response_stream::Channel, one_of_mapped_pets::OneOfMappedPets; _mediaType=nothing) -> Channel{ OneOfMappedPets }, OpenAPI.Clients.ApiResponse
Expand Down
15 changes: 15 additions & 0 deletions test/client/allany/AllAnyClient/docs/OneOfBaseType.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# OneOfBaseType



## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**value** | This is a oneOf model. The value must be exactly one of the following types: Float64, String | | [optional]




[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md)


15 changes: 15 additions & 0 deletions test/client/allany/AllAnyClient/docs/TypeWithAllArrayTypes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# TypeWithAllArrayTypes


## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**oneofbase** | [**Vector{OneOfBaseType}**](OneOfBaseType.md) | | [optional] [default to nothing]
**anyofbase** | [**Vector{AnyOfBaseType}**](AnyOfBaseType.md) | | [optional] [default to nothing]
**oneofpets** | [**Vector{OneOfPets}**](OneOfPets.md) | | [optional] [default to nothing]
**anyofpets** | [**Vector{AnyOfPets}**](AnyOfPets.md) | | [optional] [default to nothing]


[[Back to Model list]](../README.md#models) [[Back to API list]](../README.md#api-endpoints) [[Back to README]](../README.md)


81 changes: 81 additions & 0 deletions test/client/allany/AllAnyClient/src/apis/api_DefaultApi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@ This can be used to construct the `OpenAPI.Clients.Client` instance.
"""
basepath(::Type{ DefaultApi }) = "http://localhost"

const _returntypes_echo_anyof_base_type_post_DefaultApi = Dict{Regex,Type}(
Regex("^" * replace("200", "x"=>".") * "\$") => AnyOfBaseType,
)

function _oacinternal_echo_anyof_base_type_post(_api::DefaultApi, any_of_base_type::AnyOfBaseType; _mediaType=nothing)
_ctx = OpenAPI.Clients.Ctx(_api.client, "POST", _returntypes_echo_anyof_base_type_post_DefaultApi, "/echo_anyof_base_type", [], any_of_base_type)
OpenAPI.Clients.set_header_accept(_ctx, ["application/json", ])
OpenAPI.Clients.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json", ] : [_mediaType])
return _ctx
end

@doc raw"""Params:
- any_of_base_type::AnyOfBaseType (required)
Return: AnyOfBaseType, OpenAPI.Clients.ApiResponse
"""
function echo_anyof_base_type_post(_api::DefaultApi, any_of_base_type::AnyOfBaseType; _mediaType=nothing)
_ctx = _oacinternal_echo_anyof_base_type_post(_api, any_of_base_type; _mediaType=_mediaType)
return OpenAPI.Clients.exec(_ctx)
end

function echo_anyof_base_type_post(_api::DefaultApi, response_stream::Channel, any_of_base_type::AnyOfBaseType; _mediaType=nothing)
_ctx = _oacinternal_echo_anyof_base_type_post(_api, any_of_base_type; _mediaType=_mediaType)
return OpenAPI.Clients.exec(_ctx, response_stream)
end

const _returntypes_echo_anyof_mapped_pets_post_DefaultApi = Dict{Regex,Type}(
Regex("^" * replace("200", "x"=>".") * "\$") => AnyOfMappedPets,
)
Expand Down Expand Up @@ -63,6 +89,58 @@ function echo_anyof_pets_post(_api::DefaultApi, response_stream::Channel, any_of
return OpenAPI.Clients.exec(_ctx, response_stream)
end

const _returntypes_echo_arrays_post_DefaultApi = Dict{Regex,Type}(
Regex("^" * replace("200", "x"=>".") * "\$") => TypeWithAllArrayTypes,
)

function _oacinternal_echo_arrays_post(_api::DefaultApi, type_with_all_array_types::TypeWithAllArrayTypes; _mediaType=nothing)
_ctx = OpenAPI.Clients.Ctx(_api.client, "POST", _returntypes_echo_arrays_post_DefaultApi, "/echo_arrays", [], type_with_all_array_types)
OpenAPI.Clients.set_header_accept(_ctx, ["application/json", ])
OpenAPI.Clients.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json", ] : [_mediaType])
return _ctx
end

@doc raw"""Params:
- type_with_all_array_types::TypeWithAllArrayTypes (required)
Return: TypeWithAllArrayTypes, OpenAPI.Clients.ApiResponse
"""
function echo_arrays_post(_api::DefaultApi, type_with_all_array_types::TypeWithAllArrayTypes; _mediaType=nothing)
_ctx = _oacinternal_echo_arrays_post(_api, type_with_all_array_types; _mediaType=_mediaType)
return OpenAPI.Clients.exec(_ctx)
end

function echo_arrays_post(_api::DefaultApi, response_stream::Channel, type_with_all_array_types::TypeWithAllArrayTypes; _mediaType=nothing)
_ctx = _oacinternal_echo_arrays_post(_api, type_with_all_array_types; _mediaType=_mediaType)
return OpenAPI.Clients.exec(_ctx, response_stream)
end

const _returntypes_echo_oneof_base_type_post_DefaultApi = Dict{Regex,Type}(
Regex("^" * replace("200", "x"=>".") * "\$") => OneOfBaseType,
)

function _oacinternal_echo_oneof_base_type_post(_api::DefaultApi, one_of_base_type::OneOfBaseType; _mediaType=nothing)
_ctx = OpenAPI.Clients.Ctx(_api.client, "POST", _returntypes_echo_oneof_base_type_post_DefaultApi, "/echo_oneof_base_type", [], one_of_base_type)
OpenAPI.Clients.set_header_accept(_ctx, ["application/json", ])
OpenAPI.Clients.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json", ] : [_mediaType])
return _ctx
end

@doc raw"""Params:
- one_of_base_type::OneOfBaseType (required)
Return: OneOfBaseType, OpenAPI.Clients.ApiResponse
"""
function echo_oneof_base_type_post(_api::DefaultApi, one_of_base_type::OneOfBaseType; _mediaType=nothing)
_ctx = _oacinternal_echo_oneof_base_type_post(_api, one_of_base_type; _mediaType=_mediaType)
return OpenAPI.Clients.exec(_ctx)
end

function echo_oneof_base_type_post(_api::DefaultApi, response_stream::Channel, one_of_base_type::OneOfBaseType; _mediaType=nothing)
_ctx = _oacinternal_echo_oneof_base_type_post(_api, one_of_base_type; _mediaType=_mediaType)
return OpenAPI.Clients.exec(_ctx, response_stream)
end

const _returntypes_echo_oneof_mapped_pets_post_DefaultApi = Dict{Regex,Type}(
Regex("^" * replace("200", "x"=>".") * "\$") => OneOfMappedPets,
)
Expand Down Expand Up @@ -115,7 +193,10 @@ function echo_oneof_pets_post(_api::DefaultApi, response_stream::Channel, one_of
return OpenAPI.Clients.exec(_ctx, response_stream)
end

export echo_anyof_base_type_post
export echo_anyof_mapped_pets_post
export echo_anyof_pets_post
export echo_arrays_post
export echo_oneof_base_type_post
export echo_oneof_mapped_pets_post
export echo_oneof_pets_post
Loading

2 comments on commit c563a12

@tanmaykm
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/91106

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.1.18 -m "<description of version>" c563a12d1d5e6d61070f1a177bad96c220f66564
git push origin v0.1.18

Please sign in to comment.