add tests, workflow for haskell samples (#16290)

This commit is contained in:
William Cheng 2023-08-10 10:42:57 +08:00 committed by GitHub
parent 9f051ec640
commit 36cb3ce6b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 864 additions and 20 deletions

36
.github/workflows/samples-haskell.yaml vendored Normal file
View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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.

View File

@ -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 -- ^

View File

@ -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 -- ^