-
Notifications
You must be signed in to change notification settings - Fork 26
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
How to add route-based info using servant API types? #6
Comments
Hi! What information do you want to add to your API? Generally, the method to do this is to introduce your own combinator, say instance HasOpenApi api => HasOpenApi (WithSomeInfo :> api) where
toOpenApi _ = toOpenApi @api Proxy
& description ?~ "Something" -- for example Actually, some combinators from Servant, like |
Right... Now i am experimenting with |
Basically, you replace type Api = UVerb 'GET '[JSON] '[ResOK, ResError]
data ResOK = ...
deriving HasStatus via (WithStatus 200 ResOK)
data ResOK = ...
deriving HasStatus via (WithStatus 400 ResError) I personally like this style, but alternatively you can do Note that currently Also, it is possible to make combinators injecting results to whole sub-apis, in style of |
Hi, i see where your suggestions are going, but i was not successful in getting them to run, yet. let me show you where i am with an example: {-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module MyApi where
import Data.Aeson
import Data.Aeson.Casing
import Data.OpenApi
import Data.Proxy (Proxy (..))
import Data.Text (Text)
import qualified Data.Text as Text
import GHC.Generics
import Servant.API
import Servant.Docs
-- for openapi things
import Control.Lens
import Servant.OpenApi
-- these imports are for the `Foo` thing
import Data.Typeable (Typeable)
import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
-- for pretty printing the api
import Data.Aeson.Encode.Pretty
import qualified Data.ByteString.Lazy.Char8 as BSL
data Thing = Thing
{ thingName :: String
, thingColor :: String
, thingWeightGrams :: Int
} deriving (Eq, Show, Generic)
instance ToJSON Thing where
toJSON = genericToJSON $ aesonPrefix snakeCase
instance FromJSON Thing where
parseJSON = genericParseJSON $ aesonPrefix snakeCase
instance ToSample Thing where
toSamples _ = singleSample $ Thing "shoe" "brown" 500
type ThingApi = ThingCreate
type ThingCreate = Summary "Create a thing"
:> "create"
:> ReqBody '[JSON] Thing
:> PostNoContent
-- :> UVerb 'POST '[JSON] '[WithStatus 200 ResOK, WithStatus 400 ResError]
data ResOK = ResOK String
deriving Generic
data ResError = ResError String
deriving Generic
thingApi :: Proxy ThingApi
thingApi = Proxy
instance ToSchema Thing where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "Description of a thing"
instance ToSchema ResOK where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "Success Response"
instance ToSchema ResError where
declareNamedSchema proxy = genericDeclareNamedSchema defaultSchemaOptions proxy
& mapped.schema.description ?~ "Error Response"
thingOpenApi :: OpenApi
thingOpenApi = toOpenApi thingApi
& info.title .~ "Thing API"
& info.version .~ "1.0"
& info.description ?~ "This API is about things"
main = BSL.putStrLn $ encodePretty thingOpenApi
looking at the openapi output, this gives me this: ...
"paths": {
"/create": {
"post": {
"summary": "Create a thing",
"responses": {
"400": {
"description": "Invalid `body`"
},
"204": {
"description": ""
}
},
... this is great already, but it's still desirable to add text to the so i understand that to get both, i can simply use :> Uverb 'POST [WithStatus 200 ResOK, WithStatus 400 ResError] (somehow i don't understand how to combine this with this way the compiler wants It would kind of help me best if there was something like: :> Uverb 'POST [
WithStatus 204 (Description "Thing was created" NoContent),
WithStatus 403 (Description "Such un-thing-like things are simply not allowed" NoContent),
WithStatus 418 (Description "Turns out i am just a teapot. Sorry." NoContent)
] which then generates an openapi spec like this: ...
"paths": {
"/create": {
"post": {
"summary": "Create a thing",
"responses": {
"403": {
"description": "Such un-thing-like things are simply not allowed"
},
"418": {
"description": "Turns out i am just a teapot. Sorry."
},
"204": {
"description": "Thing was created"
}
},
... isn't that possible somehow? |
@maksbotan i continued experimenting... so far i came up with the following: type ThingCreate = Summary "Create a thing"
:> "create"
:> ReqBody '[JSON] Thing
:> UVerb 'POST '[] '[
WithStatus 200 (NoContentDescribed "item creation successful"),
WithStatus 300 (NoContentDescribed "something something"),
]
data NoContentDescribed (desc :: Symbol)
instance (AllAccept cs, KnownNat status, OpenApiMethod method, KnownSymbol desc)
=> HasOpenApi (Verb method status cs (NoContentDescribed desc)) where
toOpenApi _ = toOpenApi (Proxy :: Proxy (Verb method status cs (Headers '[] NoContent)))
-- idea is to "attach" description after passing this through to normal nocontent answers which contain empty description
& description .~ (something with desc) Here i run into the problem, that Am i trying something that is completely unnatural (adding |
hi there,
regarding the example https://github.com/biocad/servant-openapi3/blob/master/example/src/Todo.hs
i have an API, that looks like this, if you adapt the example code:
can i now describe those 3 functions in my openapi just using the types
GetTodoList
,PostNewTodo
, andGetTodo
?i am looking for something like (function
f
would be just what i need, but it's just a rough example):there are examples which do similar things in the openapi3 docs which access the paths via
& paths .~ [("/some-path", ...description....)]
, but this would mean that i would need to duplicate the path information from the types. That would be unelegant as i would no longer have all paths defined in my central API definition.Is there a way? I am a lens newbie, so i might not have discovered the obvious way if there is one.
The text was updated successfully, but these errors were encountered: