I am going to sum up some of the changes I would like to apply. Feel free to comment on them as I this list is open for debate:
Click to expand
AllOf
A:
properties:
a:
type: string
B:
allOf:
- $ref: '#/components/schemas/A'
- properties:
b:
type: string
would become
type alias A =
{ a : String
}
type alias B =
{ a : String
, b : String
}
AllOf + discriminator
A:
required:
- type
properties:
a:
type: string
kind:
type: string
discriminator:
propertyName: kind
mapping:
b: '#/components/schemas/B'
B:
allOf:
- $ref: '#/components/schemas/A'
- properties:
b:
type: string
would become
type A
= A BaseA
| AB B
type alias BaseA =
{ a : String
, kind : String
}
type alias B =
{ baseA : BaseA
, b : String
}
OneOf
A:
properties:
a:
type: string
B:
oneOf:
- $ref: '#/components/schemas/A'
would become
type alias A =
{ a : String
}
type B
= BA A
If the discriminator is present, its value will be used for decoding. Otherwise Decode.oneOf
is used.
Enum
Foo:
type: string
enum: [bar, baz]
would become
type Foo
= FooBar
| FooBaz
Recursive types
Comment:
required:
- message
- responses
properties:
message:
type: string
responses:
$ref: '#/components/schemas/Comment'
would become something like
type alias Comment =
{ message : String
, responses : CommentList
}
type CommentList
= CommentList (List Comment)
For indirect recursive types the first idea to use an additional type for each circular referring property, i.e.:
Comment:
required:
- message
- responses
properties:
message:
type: string
responses:
type: array
items:
$ref: '#/components/schemas/Response'
Response:
required:
- comment
properties:
comment:
$ref: '#/components/schemas/Comment'
would become something like
type alias Comment =
{ message : String
, responses : ResponseList
}
type alias Response =
{ comment : CommentType
}
type ResponseList
= ResponseList (List Response)
type CommentType
= CommentType Comment
Variantions on this are also possible:
- always wrap the base type only:
type CommentType = CommentType Comment
type ResponseType = ResponseType Response
- make a wrapping type for each property:
type CommentResponses = CommentResponses (List Response)
type ResponseComment = ResponseComment Comment
I am not sure yet what gives the nicest result.
Request
The Request
module would be something like
module Api.Request exposing (Request, request, with...)
type Request a =
Request
{ method : String
, headers : List Http.Header
, basePath : String
, pathParams : List String
, queryParams : List Url.Builder.QueryParameter
, body : Http.Body
, createExpect : (Result Http.Error a -> msg) -> Http.Expect msg
, timeout : Maybe Float
, tracker : Maybe String
}
request : String -> List (Maybe Http.Header) -> List String -> List (Maybe Url.Builder.QueryParameter) -> Http.Body -> ((Result Http.Error a -> msg) -> Http.Expect msg) -> Request a
send : Request a -> (Result Http.Error a -> msg) -> Cmd msg
withBasePath : String -> Request a -> Request a
withTimeout : Float -> Request a -> Request a
withTracker : String -> Request a -> Request a
withHeader : Http.Header -> Request a -> Request a
withHeaders : List Http.Header -> Request a -> Request a
The Request
type is used for operations, e.g.
/users/{userId}:
put:
tags:
- user
parameters:
- name: userId
in: path
required: true
schema:
type: string
format: uuid
- name: dry-run
in: query
required: false
schema:
type: boolean
operationId: updateUser
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/User'
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/User'
would become something like
module Api.Request.User exposing (updateUser)
updateUser : String -> Maybe Bool -> User -> Request User
updateUser = ...
Please let me know what you think. All suggestions are welcome!