diff --git a/.github/workflows/samples-haskell.yaml b/.github/workflows/samples-haskell.yaml new file mode 100644 index 000000000000..ebcbaad8e74d --- /dev/null +++ b/.github/workflows/samples-haskell.yaml @@ -0,0 +1,36 @@ +name: Samples Haskell + +on: + push: + paths: + - samples/server/petstore/haskell-yesod/** + - samples/server/petstore/haskell-servant/** + - samples/client/petstore/haskell-http-client/** + pull_request: + paths: + - samples/server/petstore/haskell-yesod/** + - samples/server/petstore/haskell-servant/** + - samples/client/petstore/haskell-http-client/** +jobs: + build: + name: Build stack projects + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sample: + # servers + - samples/server/petstore/haskell-yesod/ + - samples/server/petstore/haskell-servant/ + - samples/client/petstore/haskell-http-client/ + steps: + - uses: actions/checkout@v3 + - uses: haskell/actions/setup@v2 + with: + # ghc-version: '8.8.4' # Exact version of ghc to use + # cabal-version: 'latest'. Omitted, but defaults to 'latest' + enable-stack: true + stack-version: 'latest' + - name: stack test + working-directory: ${{ matrix.sample }} + run: stack test diff --git a/bin/configs/haskell-servant.yaml b/bin/configs/haskell-servant.yaml index 1419e5490979..9c88686b3d7c 100644 --- a/bin/configs/haskell-servant.yaml +++ b/bin/configs/haskell-servant.yaml @@ -1,4 +1,4 @@ generatorName: haskell outputDir: samples/server/petstore/haskell-servant -inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml +inputSpec: modules/openapi-generator/src/test/resources/3_0/haskell/petstore.yaml templateDir: modules/openapi-generator/src/main/resources/haskell-servant diff --git a/bin/configs/haskell-yesod-petstore-new.yaml b/bin/configs/haskell-yesod.yaml similarity index 71% rename from bin/configs/haskell-yesod-petstore-new.yaml rename to bin/configs/haskell-yesod.yaml index f7ae3890cdf9..60763aa57937 100644 --- a/bin/configs/haskell-yesod-petstore-new.yaml +++ b/bin/configs/haskell-yesod.yaml @@ -1,6 +1,6 @@ generatorName: haskell-yesod outputDir: samples/server/petstore/haskell-yesod -inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml +inputSpec: modules/openapi-generator/src/test/resources/3_0/haskell/petstore.yaml templateDir: modules/openapi-generator/src/main/resources/haskell-yesod additionalProperties: hideGenerationTimestamp: "true" diff --git a/modules/openapi-generator/src/test/resources/3_0/haskell/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/haskell/petstore.yaml new file mode 100644 index 000000000000..0c3985e5782e --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/haskell/petstore.yaml @@ -0,0 +1,754 @@ +openapi: 3.0.0 +servers: + - url: 'http://petstore.swagger.io/v2' +info: + description: >- + This is a sample server Petstore server. For this sample, you can use the api key + `special-key` to test the authorization filters. + version: 1.0.0 + title: OpenAPI Petstore + license: + name: Apache-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' +tags: + - name: pet + description: Everything about your Pets + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user +paths: + /pet: + post: + tags: + - pet + summary: Add a new pet to the store + description: '' + operationId: addPet + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + put: + tags: + - pet + summary: Update an existing pet + description: '' + operationId: updatePet + externalDocs: + url: "http://petstore.swagger.io/v2/doc/updatePet" + description: "API documentation for the updatePet operation" + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + $ref: '#/components/requestBodies/Pet' + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + style: form + explode: false + deprecated: true + schema: + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'read:pets' + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: >- + Multiple tags can be provided with comma separated strings. Use tag1, + tag2, tag3 for testing. + operationId: findPetsByTags + parameters: + - name: tags + in: query + description: Tags to filter by + required: true + style: form + explode: false + schema: + type: array + items: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid tag value + security: + - petstore_auth: + - 'read:pets' + deprecated: true + '/pet/{petId}': + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: integer + format: int64 + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + name: + description: Updated name of the pet + type: string + status: + description: Updated status of the pet + type: string + delete: + tags: + - pet + summary: Deletes a pet + description: '' + operationId: deletePet + parameters: + - name: api_key + in: header + required: false + schema: + type: string + - name: petId + in: path + description: Pet id to delete + required: true + schema: + type: integer + format: int64 + responses: + '400': + description: Invalid pet value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + '/pet/{petId}/uploadImage': + post: + tags: + - pet + summary: uploads an image + description: '' + operationId: uploadFile + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + additionalMetadata: + description: Additional data to pass to server + type: string + file: + description: file to upload + type: string + format: binary + /store/inventory: + get: + tags: + - store + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + responses: + '200': + description: successful operation + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: '' + operationId: placeOrder + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid Order + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + description: order placed for purchasing the pet + required: true + '/store/order/{orderId}': + get: + tags: + - store + summary: Find purchase order by ID + description: >- + For valid response try integer IDs with value <= 5 or > 10. Other values + will generate exceptions + operationId: getOrderById + parameters: + - name: orderId + in: path + description: ID of pet that needs to be fetched + required: true + schema: + type: integer + format: int64 + minimum: 1 + maximum: 5 + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: >- + For valid response try integer IDs with value < 1000. Anything above + 1000 or nonintegers will generate API errors + operationId: deleteOrder + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Created user object + required: true + /user/createWithArray: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithArrayInput + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithListInput + responses: + default: + description: successful operation + security: + - api_key: [] + requestBody: + $ref: '#/components/requestBodies/UserArray' + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: '' + operationId: loginUser + parameters: + - name: username + in: query + description: The user name for login + required: true + schema: + type: string + pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' + - name: password + in: query + description: The password for login in clear text + required: true + schema: + type: string + responses: + '200': + description: successful operation + headers: + Set-Cookie: + description: >- + Cookie authentication key for use with the `api_key` + apiKey authentication. + schema: + type: string + example: AUTH_KEY=abcde12345; Path=/; HttpOnly + X-Rate-Limit: + description: calls per hour allowed by the user + schema: + type: integer + format: int32 + X-Expires-After: + description: date in UTC when token expires + schema: + type: string + format: date-time + content: + application/xml: + schema: + type: string + application/json: + schema: + type: string + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: '' + operationId: logoutUser + responses: + default: + description: successful operation + security: + - api_key: [] + '/user/{username}': + get: + tags: + - user + summary: Get user by user name + description: '' + operationId: getUserByName + parameters: + - name: username + in: path + description: The name that needs to be fetched. Use user1 for testing. + required: true + schema: + type: string + responses: + '200': + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + parameters: + - name: username + in: path + description: name that need to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + security: + - api_key: [] + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/User' + description: Updated user object + required: true + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + schema: + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found + security: + - api_key: [] +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' +components: + requestBodies: + UserArray: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + description: List of user object + required: true + Pet: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + description: Pet object that needs to be added to the store + required: true + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + schemas: + Order: + title: Pet Order + description: An order for a pets from the pet store + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + title: Pet category + description: A category for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$' + xml: + name: Category + User: + title: a User + description: A User who is purchasing from the pet store + type: object + properties: + id: + type: integer + format: int64 + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + title: Pet Tag + description: A tag for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + title: a Pet + description: A pet for sale in the pet store + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + category: + $ref: '#/components/schemas/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + deprecated: true + enum: + - available + - pending + - sold + xml: + name: Pet + ApiResponse: + title: An uploaded response + description: Describes the result of uploading an image resource + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string + SpecialCharacters: + type: object + properties: + "\"": + type: string + description: double quote + "\\": + type: string + description: backslash + required: + - "\"" + - "\\" + description: description diff --git a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs index 88e7aaa8764d..12a83e1a110a 100644 --- a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs +++ b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/API.hs @@ -146,26 +146,26 @@ formatSeparatedQueryList char = T.intercalate (T.singleton char) . map toQueryPa -- | Servant type-level API, generated from the OpenAPI spec for OpenAPIPetstore. type OpenAPIPetstoreAPI - = Protected :> "pet" :> ReqBody '[JSON] Pet :> Verb 'POST 200 '[JSON] NoContent -- 'addPet' route + = Protected :> "pet" :> ReqBody '[JSON] Pet :> Verb 'POST 200 '[JSON] Pet -- 'addPet' route :<|> Protected :> "pet" :> Capture "petId" Integer :> Header "api_key" Text :> Verb 'DELETE 200 '[JSON] NoContent -- 'deletePet' route :<|> Protected :> "pet" :> "findByStatus" :> QueryParam "status" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByStatus' route :<|> Protected :> "pet" :> "findByTags" :> QueryParam "tags" (QueryList 'CommaSeparated (Text)) :> Verb 'GET 200 '[JSON] [Pet] -- 'findPetsByTags' route :<|> Protected :> "pet" :> Capture "petId" Integer :> Verb 'GET 200 '[JSON] Pet -- 'getPetById' route - :<|> Protected :> "pet" :> ReqBody '[JSON] Pet :> Verb 'PUT 200 '[JSON] NoContent -- 'updatePet' route + :<|> Protected :> "pet" :> ReqBody '[JSON] Pet :> Verb 'PUT 200 '[JSON] Pet -- 'updatePet' route :<|> Protected :> "pet" :> Capture "petId" Integer :> ReqBody '[FormUrlEncoded] FormUpdatePetWithForm :> Verb 'POST 200 '[JSON] NoContent -- 'updatePetWithForm' route :<|> Protected :> "pet" :> Capture "petId" Integer :> "uploadImage" :> ReqBody '[FormUrlEncoded] FormUploadFile :> Verb 'POST 200 '[JSON] ApiResponse -- 'uploadFile' route :<|> "store" :> "order" :> Capture "orderId" Text :> Verb 'DELETE 200 '[JSON] NoContent -- 'deleteOrder' route :<|> Protected :> "store" :> "inventory" :> Verb 'GET 200 '[JSON] ((Map.Map String Int)) -- 'getInventory' route :<|> "store" :> "order" :> Capture "orderId" Integer :> Verb 'GET 200 '[JSON] Order -- 'getOrderById' route :<|> "store" :> "order" :> ReqBody '[JSON] Order :> Verb 'POST 200 '[JSON] Order -- 'placeOrder' route - :<|> "user" :> ReqBody '[JSON] User :> Verb 'POST 200 '[JSON] NoContent -- 'createUser' route - :<|> "user" :> "createWithArray" :> ReqBody '[JSON] [User] :> Verb 'POST 200 '[JSON] NoContent -- 'createUsersWithArrayInput' route - :<|> "user" :> "createWithList" :> ReqBody '[JSON] [User] :> Verb 'POST 200 '[JSON] NoContent -- 'createUsersWithListInput' route - :<|> "user" :> Capture "username" Text :> Verb 'DELETE 200 '[JSON] NoContent -- 'deleteUser' route + :<|> Protected :> "user" :> ReqBody '[JSON] User :> Verb 'POST 200 '[JSON] NoContent -- 'createUser' route + :<|> Protected :> "user" :> "createWithArray" :> ReqBody '[JSON] [User] :> Verb 'POST 200 '[JSON] NoContent -- 'createUsersWithArrayInput' route + :<|> Protected :> "user" :> "createWithList" :> ReqBody '[JSON] [User] :> Verb 'POST 200 '[JSON] NoContent -- 'createUsersWithListInput' route + :<|> Protected :> "user" :> Capture "username" Text :> Verb 'DELETE 200 '[JSON] NoContent -- 'deleteUser' route :<|> "user" :> Capture "username" Text :> Verb 'GET 200 '[JSON] User -- 'getUserByName' route - :<|> "user" :> "login" :> QueryParam "username" Text :> QueryParam "password" Text :> Verb 'GET 200 '[JSON] (Headers '[Header "X-Rate-Limit" Int, Header "X-Expires-After" UTCTime] Text) -- 'loginUser' route - :<|> "user" :> "logout" :> Verb 'GET 200 '[JSON] NoContent -- 'logoutUser' route - :<|> "user" :> Capture "username" Text :> ReqBody '[JSON] User :> Verb 'PUT 200 '[JSON] NoContent -- 'updateUser' route + :<|> "user" :> "login" :> QueryParam "username" Text :> QueryParam "password" Text :> Verb 'GET 200 '[JSON] (Headers '[Header "Set-Cookie" Text, Header "X-Rate-Limit" Int, Header "X-Expires-After" UTCTime] Text) -- 'loginUser' route + :<|> Protected :> "user" :> "logout" :> Verb 'GET 200 '[JSON] NoContent -- 'logoutUser' route + :<|> Protected :> "user" :> Capture "username" Text :> ReqBody '[JSON] User :> Verb 'PUT 200 '[JSON] NoContent -- 'updateUser' route :<|> Raw @@ -186,26 +186,26 @@ newtype OpenAPIPetstoreClientError = OpenAPIPetstoreClientError ClientError -- is a backend that executes actions by sending HTTP requests (see @createOpenAPIPetstoreClient@). Alternatively, provided -- a backend, the API can be served using @runOpenAPIPetstoreMiddlewareServer@. data OpenAPIPetstoreBackend a m = OpenAPIPetstoreBackend - { addPet :: a -> Pet -> m NoContent{- ^ -} + { addPet :: a -> Pet -> m Pet{- ^ -} , deletePet :: a -> Integer -> Maybe Text -> m NoContent{- ^ -} , findPetsByStatus :: a -> Maybe [Text] -> m [Pet]{- ^ Multiple status values can be provided with comma separated strings -} , findPetsByTags :: a -> Maybe [Text] -> m [Pet]{- ^ Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. -} , getPetById :: a -> Integer -> m Pet{- ^ Returns a single pet -} - , updatePet :: a -> Pet -> m NoContent{- ^ -} + , updatePet :: a -> Pet -> m Pet{- ^ -} , updatePetWithForm :: a -> Integer -> FormUpdatePetWithForm -> m NoContent{- ^ -} , uploadFile :: a -> Integer -> FormUploadFile -> m ApiResponse{- ^ -} , deleteOrder :: Text -> m NoContent{- ^ For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors -} , getInventory :: a -> m ((Map.Map String Int)){- ^ Returns a map of status codes to quantities -} , getOrderById :: Integer -> m Order{- ^ For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions -} , placeOrder :: Order -> m Order{- ^ -} - , createUser :: User -> m NoContent{- ^ This can only be done by the logged in user. -} - , createUsersWithArrayInput :: [User] -> m NoContent{- ^ -} - , createUsersWithListInput :: [User] -> m NoContent{- ^ -} - , deleteUser :: Text -> m NoContent{- ^ This can only be done by the logged in user. -} + , createUser :: a -> User -> m NoContent{- ^ This can only be done by the logged in user. -} + , createUsersWithArrayInput :: a -> [User] -> m NoContent{- ^ -} + , createUsersWithListInput :: a -> [User] -> m NoContent{- ^ -} + , deleteUser :: a -> Text -> m NoContent{- ^ This can only be done by the logged in user. -} , getUserByName :: Text -> m User{- ^ -} - , loginUser :: Maybe Text -> Maybe Text -> m (Headers '[Header "X-Rate-Limit" Int, Header "X-Expires-After" UTCTime] Text){- ^ -} - , logoutUser :: m NoContent{- ^ -} - , updateUser :: Text -> User -> m NoContent{- ^ This can only be done by the logged in user. -} + , loginUser :: Maybe Text -> Maybe Text -> m (Headers '[Header "Set-Cookie" Text, Header "X-Rate-Limit" Int, Header "X-Expires-After" UTCTime] Text){- ^ -} + , logoutUser :: a -> m NoContent{- ^ -} + , updateUser :: a -> Text -> User -> m NoContent{- ^ This can only be done by the logged in user. -} } -- | Authentication settings for OpenAPIPetstore. diff --git a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs index 5b34009d2ff5..5b392137005b 100644 --- a/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs +++ b/samples/server/petstore/haskell-servant/lib/OpenAPIPetstore/Types.hs @@ -8,6 +8,7 @@ module OpenAPIPetstore.Types ( Category (..), Order (..), Pet (..), + SpecialCharacters (..), Tag (..), User (..), ) where @@ -159,6 +160,34 @@ optionsPet = ] +-- | description +data SpecialCharacters = SpecialCharacters + { specialCharactersDoubleQuote :: Text -- ^ double quote + , specialCharactersBackSlash :: Text -- ^ backslash + } deriving (Show, Eq, Generic, Data) + +instance FromJSON SpecialCharacters where + parseJSON = genericParseJSON optionsSpecialCharacters +instance ToJSON SpecialCharacters where + toJSON = genericToJSON optionsSpecialCharacters +instance ToSchema SpecialCharacters where + declareNamedSchema = Swagger.genericDeclareNamedSchema + $ Swagger.fromAesonOptions + $ optionsSpecialCharacters + +optionsSpecialCharacters :: Options +optionsSpecialCharacters = + defaultOptions + { omitNothingFields = True + , fieldLabelModifier = \s -> fromMaybe ("did not find JSON field name for " ++ show s) $ lookup s table + } + where + table = + [ ("specialCharactersDoubleQuote", "\"") + , ("specialCharactersBackSlash", "\\") + ] + + -- | A tag for a pet data Tag = Tag { tagId :: Maybe Integer -- ^ diff --git a/samples/server/petstore/haskell-yesod/src/OpenAPIPetstore/Types.hs b/samples/server/petstore/haskell-yesod/src/OpenAPIPetstore/Types.hs index 54ba54fd7686..2f296b0ea103 100644 --- a/samples/server/petstore/haskell-yesod/src/OpenAPIPetstore/Types.hs +++ b/samples/server/petstore/haskell-yesod/src/OpenAPIPetstore/Types.hs @@ -8,6 +8,7 @@ module OpenAPIPetstore.Types ( Category (..), Order (..), Pet (..), + SpecialCharacters (..), Tag (..), User (..), ) where @@ -138,6 +139,30 @@ optionsPet = ] +-- | description +data SpecialCharacters = SpecialCharacters + { specialCharactersDoubleQuote :: Text -- ^ double quote + , specialCharactersBackSlash :: Text -- ^ backslash + } deriving (Show, Eq, Generic) + +instance FromJSON SpecialCharacters where + parseJSON = genericParseJSON optionsSpecialCharacters +instance ToJSON SpecialCharacters where + toJSON = genericToJSON optionsSpecialCharacters + +optionsSpecialCharacters :: Options +optionsSpecialCharacters = + defaultOptions + { omitNothingFields = True + , fieldLabelModifier = \s -> fromMaybe ("did not find JSON field name for " ++ show s) $ List.lookup s table + } + where + table = + [ ("specialCharactersDoubleQuote", "\"") + , ("specialCharactersBackSlash", "\\") + ] + + -- | A tag for a pet data Tag = Tag { tagId :: Maybe Int64 -- ^