Skip to content

Commit

Permalink
Add multiple servers as an option
Browse files Browse the repository at this point in the history
  • Loading branch information
miniBill committed Jun 25, 2024
1 parent 338ef1e commit 109699d
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 37 deletions.
34 changes: 31 additions & 3 deletions src/Cli.elm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type alias CliOptions =
, swaggerConversionUrl : String
, swaggerConversionCommand : Maybe String
, swaggerConversionCommandArgs : List String
, server : Maybe String
, server : OpenApi.Generate.Server
}


Expand Down Expand Up @@ -71,7 +71,9 @@ program =
|> Cli.OptionsParser.with
(Cli.Option.keywordArgList "swagger-conversion-command-args")
|> Cli.OptionsParser.with
(Cli.Option.optionalKeywordArg "server")
(Cli.Option.optionalKeywordArg "server"
|> Cli.Option.validateMap serverValidation
)
|> Cli.OptionsParser.withDoc """
options:
Expand All @@ -91,6 +93,13 @@ program =
If not specified this will be extracted from the OAS
or default to root of the web application.
You can pass in an object to define multiple servers, like
{"dev": "http://localhost", "prod": "https://example.com"}.
This will add a `server` parameter to functions and define
a `Servers` module with your servers. You can pass in an
empty object if you have fully dynamic servers.
--auto-convert-swagger If passed in, and a Swagger doc is encountered,
will attempt to convert it to an Open API file.
If not passed in, and a Swagger doc is encountered,
Expand Down Expand Up @@ -148,6 +157,25 @@ effectTypeValidation effectType =
Err <| "Unexpected effect type: " ++ effectType


serverValidation : Maybe String -> Result String OpenApi.Generate.Server
serverValidation server =
case Maybe.withDefault "" server of
"" ->
Ok OpenApi.Generate.Default

input ->
case Json.Decode.decodeString (Json.Decode.dict Json.Decode.string) input of
Ok servers ->
Ok <| OpenApi.Generate.Multiple servers

Err _ ->
if String.startsWith "{" input then
Err <| "Invalid JSON: " ++ input

else
Ok <| OpenApi.Generate.Single input


run : Pages.Script.Script
run =
Pages.Script.withCliOptions program
Expand Down Expand Up @@ -354,7 +382,7 @@ generateFileFromOpenApiSpec :
{ outputModuleName : Maybe String
, generateTodos : Maybe String
, effectTypes : List OpenApi.Generate.EffectType
, server : Maybe String
, server : OpenApi.Generate.Server
}
-> OpenApi.OpenApi
-> BackendTask.BackendTask FatalError.FatalError ( List Elm.File, List CliMonad.Message )
Expand Down
4 changes: 4 additions & 0 deletions src/Common.elm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Module
| Types
| Api
| Common
| Servers


moduleToNamespace : List String -> Module -> List String
Expand All @@ -36,6 +37,9 @@ moduleToNamespace namespace module_ =
Api ->
namespace ++ [ "Api" ]

Servers ->
namespace ++ [ "Servers" ]

Common ->
[ "OpenApi", "Common" ]

Expand Down
106 changes: 73 additions & 33 deletions src/OpenApi/Generate.elm
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module OpenApi.Generate exposing
( ContentSchema(..)
, EffectType(..)
, Mime
, Server(..)
, files
, sanitizeModuleName
)
Expand Down Expand Up @@ -72,6 +73,12 @@ type ContentSchema
| BytesContent Mime


type Server
= Default
| Single String
| Multiple (Dict.Dict String String)


type alias AuthorizationInfo =
{ headers : Elm.Expression -> List ( Elm.Expression, Elm.Expression )
, params : List ( String, Elm.Annotation.Annotation )
Expand All @@ -83,7 +90,7 @@ files :
{ namespace : List String
, generateTodos : Bool
, effectTypes : List EffectType
, server : Maybe String
, server : Server
}
-> OpenApi.OpenApi
-> Result CliMonad.Message ( List Elm.File, List CliMonad.Message )
Expand Down Expand Up @@ -151,6 +158,25 @@ files { namespace, generateTodos, effectTypes, server } apiSpec =
}
)
]
++ (case server of
Multiple servers ->
servers
|> Dict.toList
|> List.map
(\( key, value ) ->
( Common.Servers
, Elm.string value
|> Elm.declaration key
|> Elm.exposeWith
{ exposeConstructor = True
, group = Just "Servers"
}
)
)

_ ->
[]
)
in
( allDecls
|> List.Extra.gatherEqualsBy Tuple.first
Expand Down Expand Up @@ -223,7 +249,7 @@ formatModuleDocs =
)


pathDeclarations : Maybe String -> List EffectType -> List String -> CliMonad (List ( Common.Module, Elm.Declaration ))
pathDeclarations : Server -> List EffectType -> List String -> CliMonad (List ( Common.Module, Elm.Declaration ))
pathDeclarations server effectTypes namespace =
CliMonad.fromApiSpec OpenApi.paths
|> CliMonad.andThen
Expand Down Expand Up @@ -399,7 +425,7 @@ requestBodyToDeclarations namespace name reference =
|> CliMonad.withPath name


toRequestFunctions : Maybe String -> List EffectType -> List String -> String -> String -> OpenApi.Operation.Operation -> CliMonad (List ( Common.Module, Elm.Declaration ))
toRequestFunctions : Server -> List EffectType -> List String -> String -> String -> OpenApi.Operation.Operation -> CliMonad (List ( Common.Module, Elm.Declaration ))
toRequestFunctions server effectTypes namespace method pathUrl operation =
let
functionName : String
Expand Down Expand Up @@ -666,6 +692,7 @@ toRequestFunctions server effectTypes namespace method pathUrl operation =
, errorTypeAnnotation = errorTypeAnnotation
, authorizationInfo = auth
, bodyParams = params
, server = server
}
)
)
Expand All @@ -679,7 +706,7 @@ toRequestFunctions server effectTypes namespace method pathUrl operation =
|> CliMonad.withPath pathUrl


replacedUrl : Maybe String -> List String -> String -> OpenApi.Operation.Operation -> CliMonad (Elm.Expression -> Elm.Expression)
replacedUrl : Server -> List String -> String -> OpenApi.Operation.Operation -> CliMonad (Elm.Expression -> Elm.Expression)
replacedUrl server namespace pathUrl operation =
let
params : List (OpenApi.Reference.ReferenceOr OpenApi.Parameter.Parameter)
Expand Down Expand Up @@ -750,35 +777,40 @@ replacedUrl server namespace pathUrl operation =
OpenApi.servers
|> CliMonad.fromApiSpec
|> CliMonad.map
(\servers ->
\config ->
let
initialUrl : String
initialUrl =
case server of
Just cliServer ->
if String.startsWith "/" pathUrl then
cliServer ++ pathUrl

else
cliServer ++ "/" ++ pathUrl

Nothing ->
case servers of
[] ->
pathUrl

firstServer :: _ ->
if String.startsWith "/" pathUrl then
OpenApi.Server.url firstServer ++ pathUrl
(\servers config ->
let
initialUrl : Elm.Expression
initialUrl =
let
appendPath : String -> Elm.Expression
appendPath resolvedServer =
if String.startsWith "/" pathUrl then
Elm.string <| resolvedServer ++ pathUrl

else
OpenApi.Server.url firstServer ++ "/" ++ pathUrl
in
List.foldl
(\( replacement, _ ) -> replacement config)
(Elm.string initialUrl)
replacements
else
Elm.string <| resolvedServer ++ "/" ++ pathUrl
in
case server of
Single cliServer ->
cliServer |> appendPath

Default ->
case servers of
[] ->
"" |> appendPath

firstServer :: _ ->
OpenApi.Server.url firstServer |> appendPath

Multiple _ ->
Elm.Op.append
(Elm.get "server" config)
(appendPath "")
in
List.foldl
(\( replacement, _ ) -> replacement config)
initialUrl
replacements
)

else
Expand Down Expand Up @@ -1121,12 +1153,20 @@ toConfigParamAnnotation :
, errorTypeAnnotation : Elm.Annotation.Annotation
, authorizationInfo : AuthorizationInfo
, bodyParams : List ( String, Elm.Annotation.Annotation )
, server : Server
}
-> CliMonad ({ requireToMsg : Bool } -> Elm.Annotation.Annotation)
toConfigParamAnnotation namespace options =
CliMonad.map
(\urlParams { requireToMsg } ->
(options.authorizationInfo.params
((case options.server of
Multiple _ ->
[ ( "server", Elm.Annotation.string ) ]

_ ->
[]
)
++ options.authorizationInfo.params
++ (if requireToMsg then
[ ( "toMsg"
, Elm.Annotation.function
Expand Down
2 changes: 1 addition & 1 deletion tests/Test/OpenApi/Generate.elm
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ suite =
{ namespace = namespace
, generateTodos = False
, effectTypes = [ OpenApi.Generate.Cmd, OpenApi.Generate.Task ]
, server = Nothing
, server = OpenApi.Generate.Default
}
oas
in
Expand Down

0 comments on commit 109699d

Please sign in to comment.