Skip to content

URL encoded bodies #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Support for params being passed in the header
- Support for `type : null`
- Support for `const : <value>`
- Support for `application/x-www-form-urlencoded` bodies
- [Support for `additionalProperties` in objects](https://github.com/wolfadex/elm-open-api-cli/pull/184). [Adam DiCarlo](https://github.com/adamdicarlo0)

## [0.7.0] - 2024-09-23
Expand Down
101 changes: 93 additions & 8 deletions src/OpenApi/Generate.elm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Elm.Annotation
import Elm.Arg
import Elm.Case
import Elm.Declare
import Elm.Let
import Elm.Op
import FastDict
import FastSet
Expand All @@ -37,6 +38,7 @@ import Gen.OpenApi.Common
import Gen.Result
import Gen.String
import Gen.Task
import Gen.Url
import Gen.Url.Builder
import Json.Decode
import Json.Schema.Definitions
Expand Down Expand Up @@ -70,6 +72,7 @@ type ContentSchema
= EmptyContent
| JsonContent Common.Type
| StringContent Mime
| UrlEncodedContent Common.Type
| BytesContent Mime


Expand Down Expand Up @@ -624,14 +627,56 @@ toRequestFunctions server effectTypes method pathUrl operation =
let
encoded : Elm.Expression
encoded =
encoder <| Elm.get "body" config
Elm.get "body" config
|> encoder
in
{ core = Gen.Http.jsonBody encoded
, elmPages = Gen.BackendTask.Http.jsonBody encoded
, lamderaProgramTest = Gen.Effect.Http.jsonBody encoded
}
)

UrlEncodedContent type_ ->
SchemaUtils.typeToEncoder True type_
|> CliMonad.map
(\encoder config ->
let
encoded : Elm.Expression
encoded =
Elm.get "body" config
|> encoder
|> Gen.Json.Decode.decodeValue (Gen.Json.Decode.dict Gen.Json.Decode.value)
|> Gen.Result.map
(\keyValues ->
keyValues
|> Gen.Dict.toList
|> Gen.List.call_.map
(Elm.fn ( "keyVal", Nothing )
(\keyVal ->
Elm.Let.letIn
(\( key, value ) ->
Gen.String.call_.concat
(Elm.list
[ Gen.Url.call_.percentEncode key
, Elm.string "="
, Gen.Url.call_.percentEncode (Gen.Json.Encode.encode 0 value)
]
)
)
|> Elm.Let.tuple "key" "value" keyVal
|> Elm.Let.toExpression
)
)
|> Gen.String.call_.join (Elm.string "&")
)
|> Gen.Result.withDefault (Elm.string "")
in
{ core = Gen.Http.call_.stringBody (Elm.string "application/x-www-form-urlencoded") encoded
, elmPages = Gen.Http.call_.stringBody (Elm.string "application/x-www-form-urlencoded") encoded
, lamderaProgramTest = Gen.Http.call_.stringBody (Elm.string "application/x-www-form-urlencoded") encoded
}
)

StringContent mime ->
CliMonad.succeed <|
\config ->
Expand Down Expand Up @@ -668,6 +713,10 @@ toRequestFunctions server effectTypes method pathUrl operation =
SchemaUtils.typeToAnnotationWithNullable True type_
|> CliMonad.map (\annotation -> [ ( Common.UnsafeName "body", annotation ) ])

UrlEncodedContent type_ ->
SchemaUtils.typeToAnnotationWithNullable True type_
|> CliMonad.map (\annotation -> [ ( Common.UnsafeName "body", annotation ) ])

StringContent _ ->
CliMonad.succeed [ ( Common.UnsafeName "body", Elm.Annotation.string ) ]

Expand Down Expand Up @@ -1806,13 +1855,22 @@ contentToContentSchema qualify content =
stringContent "text/plain" htmlSchema

Nothing ->
let
msg : String
msg =
"The content doesn't have an application/json, text/html or text/plain option, it has " ++ String.join ", " (Dict.keys content)
in
fallback
|> Maybe.withDefault (CliMonad.fail msg)
case Dict.get "application/x-www-form-urlencoded" content of
Just urlEncodedSchema ->
CliMonad.succeed urlEncodedSchema
|> CliMonad.stepOrFail "The request's application/x-www-form-urlencoded content option doesn't have a schema"
(OpenApi.MediaType.schema >> Maybe.map OpenApi.Schema.get)
|> CliMonad.andThen (SchemaUtils.schemaToType qualify)
|> CliMonad.map (\{ type_ } -> UrlEncodedContent type_)

Nothing ->
let
msg : String
msg =
"The content doesn't have an application/json, text/html, text/plain, or application/x-www-form-urlencoded option, it has " ++ String.join ", " (Dict.keys content)
in
fallback
|> Maybe.withDefault (CliMonad.fail msg)

stringContent : String -> OpenApi.MediaType.MediaType -> CliMonad ContentSchema
stringContent mime htmlSchema =
Expand Down Expand Up @@ -2491,6 +2549,10 @@ operationToTypesExpectAndResolver functionName operation =
SchemaUtils.typeToDecoder True type_
|> CliMonad.andThen common

UrlEncodedContent type_ ->
SchemaUtils.typeToDecoder True type_
|> CliMonad.andThen common

StringContent _ ->
CliMonad.succeed Gen.Json.Decode.string
|> CliMonad.andThen common
Expand Down Expand Up @@ -2551,6 +2613,11 @@ operationToTypesExpectAndResolver functionName operation =
(SchemaUtils.typeToAnnotationWithNullable False type_)
(SchemaUtils.typeToAnnotationWithNullable True type_)

UrlEncodedContent type_ ->
CliMonad.map2 Tuple.pair
(SchemaUtils.typeToAnnotationWithNullable False type_)
(SchemaUtils.typeToAnnotationWithNullable True type_)

StringContent _ ->
CliMonad.succeed
( Elm.Annotation.string
Expand Down Expand Up @@ -2647,6 +2714,24 @@ operationToTypesExpectAndResolver functionName operation =
errorDecoders
errorTypeDeclaration

UrlEncodedContent type_ ->
CliMonad.map3
(\successDecoder errorDecoders_ ( errorTypeDeclaration_, errorTypeAnnotation ) ->
{ successType = type_
, bodyTypeAnnotation = Elm.Annotation.string
, errorTypeDeclaration = errorTypeDeclaration_
, errorTypeAnnotation = errorTypeAnnotation
, expect = expectJsonBetter errorDecoders_ successDecoder
, resolver =
{ core = Gen.OpenApi.Common.jsonResolverCustom errorDecoders_ successDecoder
, lamderaProgramTest = Gen.OpenApi.Common.jsonResolverCustomEffect errorDecoders_ successDecoder
}
}
)
(SchemaUtils.typeToDecoder True type_)
errorDecoders
errorTypeDeclaration

StringContent _ ->
CliMonad.map2
(\errorDecoders_ ( errorTypeDeclaration_, errorTypeAnnotation ) ->
Expand Down
Loading