diff --git a/docs/generators/haskell.md b/docs/generators/haskell.md index 3692c19bb3fb..cc2dfaa0d61d 100644 --- a/docs/generators/haskell.md +++ b/docs/generators/haskell.md @@ -13,3 +13,4 @@ sidebar_label: haskell |prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false| |modelPackage|package for generated models| |null| |apiPackage|package for generated api classes| |null| +|serveStatic|serve will serve files from the directory 'static'.| |true| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellServantCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellServantCodegen.java index ec30ae275e13..8a0d09800968 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellServantCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/HaskellServantCodegen.java @@ -43,6 +43,10 @@ public class HaskellServantCodegen extends DefaultCodegen implements CodegenConf protected String apiVersion = "0.0.1"; private static final Pattern LEADING_UNDERSCORE = Pattern.compile("^_+"); + public static final String PROP_SERVE_STATIC = "serveStatic"; + public static final String PROP_SERVE_STATIC_DESC = "serve will serve files from the directory 'static'."; + public static final Boolean PROP_SERVE_STATIC_DEFAULT = Boolean.TRUE; + /** * Configures the type of generator. * @@ -183,6 +187,15 @@ public HaskellServantCodegen() { cliOptions.add(new CliOption(CodegenConstants.MODEL_PACKAGE, CodegenConstants.MODEL_PACKAGE_DESC)); cliOptions.add(new CliOption(CodegenConstants.API_PACKAGE, CodegenConstants.API_PACKAGE_DESC)); + cliOptions.add(new CliOption(PROP_SERVE_STATIC, PROP_SERVE_STATIC_DESC).defaultValue(PROP_SERVE_STATIC_DEFAULT.toString())); + } + + public void setBooleanProperty(String property, Boolean defaultValue) { + if (additionalProperties.containsKey(property)) { + additionalProperties.put(property, convertPropertyToBoolean(property)); + } else { + additionalProperties.put(property, defaultValue); + } } @Override @@ -192,6 +205,8 @@ public void processOpts() { if (StringUtils.isEmpty(System.getenv("HASKELL_POST_PROCESS_FILE"))) { LOGGER.info("Hint: Environment variable HASKELL_POST_PROCESS_FILE not defined so the Haskell code may not be properly formatted. To define it, try 'export HASKELL_POST_PROCESS_FILE=\"$HOME/.local/bin/hfmt -w\"' (Linux/Mac)"); } + + setBooleanProperty(PROP_SERVE_STATIC, PROP_SERVE_STATIC_DEFAULT); } /** diff --git a/modules/openapi-generator/src/main/resources/haskell-servant/API.mustache b/modules/openapi-generator/src/main/resources/haskell-servant/API.mustache index 4b02cb7f94ce..63a7a64576be 100644 --- a/modules/openapi-generator/src/main/resources/haskell-servant/API.mustache +++ b/modules/openapi-generator/src/main/resources/haskell-servant/API.mustache @@ -59,7 +59,8 @@ import Servant.Client (ClientEnv, Scheme (Http), C mkClientEnv, parseBaseUrl) import Servant.Client.Core (baseUrlPort, baseUrlHost) import Servant.Client.Internal.HttpClient (ClientM (..)) -import Servant.Server (Handler (..)) +import Servant.Server (Handler (..)){{#serveStatic}} +import Servant.Server.StaticFiles (serveDirectoryFileServer){{/serveStatic}} import Web.FormUrlEncoded import Web.HttpApiData @@ -129,7 +130,8 @@ formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryPa type {{title}}API = {{#apis}}{{#operations}}{{#operation}}{{& vendorExtensions.x-routeType}} -- '{{operationId}}' route{{#hasMore}} :<|> {{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}} - :<|> {{/hasMore}}{{/apis}} + :<|> {{/hasMore}}{{/apis}}{{#serveStatic}} + :<|> Raw {{/serveStatic}} {{/apiInfo}} @@ -181,7 +183,8 @@ create{{title}}Client = {{title}}Backend{..} where ({{#apis}}{{#operations}}{{#operation}}(coerce -> {{operationId}}){{#hasMore}} :<|> {{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}} :<|> - {{/hasMore}}{{/apis}}) = client (Proxy :: Proxy {{title}}API) + {{/hasMore}}{{/apis}}{{#serveStatic}} :<|> + _{{/serveStatic}}) = client (Proxy :: Proxy {{title}}API) -- | Run requests in the {{title}}Client monad. run{{title}}Client :: Config -> {{title}}Client a -> ExceptT ClientError IO a @@ -222,5 +225,6 @@ run{{title}}Server Config{..} backend = do serverFromBackend {{title}}Backend{..} = ({{#apis}}{{#operations}}{{#operation}}coerce {{operationId}}{{#hasMore}} :<|> {{/hasMore}}{{/operation}}{{/operations}}{{#hasMore}} :<|> - {{/hasMore}}{{/apis}}) + {{/hasMore}}{{/apis}}{{#serveStatic}} :<|> + serveDirectoryFileServer "static"{{/serveStatic}}) {{/apiInfo}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/HaskellServantOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/HaskellServantOptionsProvider.java index f58c4e864ca2..1ff66f0527b6 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/HaskellServantOptionsProvider.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/HaskellServantOptionsProvider.java @@ -19,6 +19,7 @@ import com.google.common.collect.ImmutableMap; import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.languages.HaskellServantCodegen; import java.util.Map; @@ -44,6 +45,7 @@ public Map createOptions() { .put(CodegenConstants.ENSURE_UNIQUE_PARAMS, ENSURE_UNIQUE_PARAMS_VALUE) .put(CodegenConstants.ALLOW_UNICODE_IDENTIFIERS, ALLOW_UNICODE_IDENTIFIERS_VALUE) .put(CodegenConstants.PREPEND_FORM_OR_BODY_PARAMETERS, PREPEND_FORM_OR_BODY_PARAMETERS_VALUE) + .put(HaskellServantCodegen.PROP_SERVE_STATIC, HaskellServantCodegen.PROP_SERVE_STATIC_DEFAULT.toString()) .build(); } diff --git a/samples/server/petstore/haskell-servant/.openapi-generator/VERSION b/samples/server/petstore/haskell-servant/.openapi-generator/VERSION index 479c313e87b9..c3a2c7076fa8 100644 --- a/samples/server/petstore/haskell-servant/.openapi-generator/VERSION +++ b/samples/server/petstore/haskell-servant/.openapi-generator/VERSION @@ -1 +1 @@ -4.0.3-SNAPSHOT \ No newline at end of file +4.2.0-SNAPSHOT \ No newline at end of file diff --git a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs index 8a65a949ea87..d1a7e6ca0f24 100644 --- a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs +++ b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs @@ -60,6 +60,7 @@ import Servant.Client (ClientEnv, Scheme (Http), C import Servant.Client.Core (baseUrlPort, baseUrlHost) import Servant.Client.Internal.HttpClient (ClientM (..)) import Servant.Server (Handler (..)) +import Servant.Server.StaticFiles (serveDirectoryFileServer) import Web.FormUrlEncoded import Web.HttpApiData @@ -137,7 +138,7 @@ type OpenAPIPetstoreAPI = "pet" :> ReqBody '[JSON] Pet :> Verb 'POST 200 '[JSON] () -- 'addPet' route :<|> "pet" :> Capture "petId" Integer :> Header "api_key" Text :> Verb 'DELETE 200 '[JSON] () -- 'deletePet' route :<|> "pet" :> "findByStatus" :> QueryParam "status" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByStatus' route - :<|> "pet" :> "findByTags" :> QueryParam "tags" (QueryList 'CommaSeparated (Text)) :> QueryParam "maxCount" Int :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByTags' route + :<|> "pet" :> "findByTags" :> QueryParam "tags" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByTags' route :<|> "pet" :> Capture "petId" Integer :> Verb 'GET 200 '[JSON] Pet -- 'getPetById' route :<|> "pet" :> ReqBody '[JSON] Pet :> Verb 'PUT 200 '[JSON] () -- 'updatePet' route :<|> "pet" :> Capture "petId" Integer :> ReqBody '[FormUrlEncoded] FormUpdatePetWithForm :> Verb 'POST 200 '[JSON] () -- 'updatePetWithForm' route @@ -154,6 +155,7 @@ type OpenAPIPetstoreAPI :<|> "user" :> "login" :> QueryParam "username" Text :> QueryParam "password" Text :> Verb 'GET 200 '[JSON] Text -- 'loginUser' route :<|> "user" :> "logout" :> Verb 'GET 200 '[JSON] () -- 'logoutUser' route :<|> "user" :> Capture "username" Text :> ReqBody '[JSON] User :> Verb 'PUT 200 '[JSON] () -- 'updateUser' route + :<|> Raw -- | Server or client configuration, specifying the host and port to query or serve on. @@ -176,7 +178,7 @@ data OpenAPIPetstoreBackend m = OpenAPIPetstoreBackend { addPet :: Pet -> m (){- ^ -} , deletePet :: Integer -> Maybe Text -> m (){- ^ -} , findPetsByStatus :: Maybe [Text] -> m [Pet]{- ^ Multiple status values can be provided with comma separated strings -} - , findPetsByTags :: Maybe [Text] -> Maybe Int -> m [Pet]{- ^ Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -} + , findPetsByTags :: Maybe [Text] -> m [Pet]{- ^ Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -} , getPetById :: Integer -> m Pet{- ^ Returns a single pet -} , updatePet :: Pet -> m (){- ^ -} , updatePetWithForm :: Integer -> FormUpdatePetWithForm -> m (){- ^ -} @@ -235,7 +237,8 @@ createOpenAPIPetstoreClient = OpenAPIPetstoreBackend{..} (coerce -> getUserByName) :<|> (coerce -> loginUser) :<|> (coerce -> logoutUser) :<|> - (coerce -> updateUser)) = client (Proxy :: Proxy OpenAPIPetstoreAPI) + (coerce -> updateUser) :<|> + _) = client (Proxy :: Proxy OpenAPIPetstoreAPI) -- | Run requests in the OpenAPIPetstoreClient monad. runOpenAPIPetstoreClient :: Config -> OpenAPIPetstoreClient a -> ExceptT ClientError IO a @@ -291,4 +294,5 @@ runOpenAPIPetstoreServer Config{..} backend = do coerce getUserByName :<|> coerce loginUser :<|> coerce logoutUser :<|> - coerce updateUser) + coerce updateUser :<|> + serveDirectoryFileServer "static") diff --git a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs index 45355fe14ac8..d4f84e4288fc 100644 --- a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs +++ b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs @@ -6,8 +6,6 @@ module OpenAPIPetstore.Types ( ApiResponse (..), Category (..), - InlineObject (..), - InlineObject1 (..), Order (..), Pet (..), Tag (..), @@ -65,38 +63,6 @@ instance ToSchema Category where $ removeFieldLabelPrefix False "category" --- | -data InlineObject = InlineObject - { inlineObjectName :: Maybe Text -- ^ Updated name of the pet - , inlineObjectStatus :: Maybe Text -- ^ Updated status of the pet - } deriving (Show, Eq, Generic, Data) - -instance FromJSON InlineObject where - parseJSON = genericParseJSON (removeFieldLabelPrefix True "inlineObject") -instance ToJSON InlineObject where - toJSON = genericToJSON (removeFieldLabelPrefix False "inlineObject") -instance ToSchema InlineObject where - declareNamedSchema = Swagger.genericDeclareNamedSchema - $ Swagger.fromAesonOptions - $ removeFieldLabelPrefix False "inlineObject" - - --- | -data InlineObject1 = InlineObject1 - { inlineObject1AdditionalMetadata :: Maybe Text -- ^ Additional data to pass to server - , inlineObject1File :: Maybe FilePath -- ^ file to upload - } deriving (Show, Eq, Generic, Data) - -instance FromJSON InlineObject1 where - parseJSON = genericParseJSON (removeFieldLabelPrefix True "inlineObject1") -instance ToJSON InlineObject1 where - toJSON = genericToJSON (removeFieldLabelPrefix False "inlineObject1") -instance ToSchema InlineObject1 where - declareNamedSchema = Swagger.genericDeclareNamedSchema - $ Swagger.fromAesonOptions - $ removeFieldLabelPrefix False "inlineObject1" - - -- | An order for a pets from the pet store data Order = Order { orderId :: Maybe Integer -- ^