How to use Swagger
The Swagger is a powerful tool to try out your servers. It provides easy to use Web UI to call routes in the server. We already have seen how to augment server with swagger. It is just a line of code:
withSwagger def server
The function withSwagger
is defined in the package mig-swagger-ui
which is re-exported by mig-server
.
In this chapter we are going to learn how to tweak and fine-tune the swagger.
Swagger config
We have used default swagger config with constant def
.
Let's look at what can be configured:
data SwaggerConfig m = SwaggerConfig
{ staticDir :: Path
-- ^ path to server swagger (default is "/swagger-ui")
, swaggerFile :: Path
-- ^ swagger file name (default is "swaggger.json")
, mapSchema :: OpenApi -> m OpenApi
-- ^ apply transformation to OpenApi schema on serving OpenApi schema.
-- it is useful to add additional info or set current date in the examples
-- or apply any real-time transformation.
}
instance (Applicative m) => Default (SwaggerConfig m) where
def =
SwaggerConfig
{ staticDir = "swagger-ui"
, swaggerFile = "swagger.json"
, mapSchema = pure
}
We can set in staticDir
at what path to serve the swagger,
how to name the swagger file with swaggerFile
and
which run-time transformation we apply to the OpenApi schema.
We can use this mapping to add useful description to the app
or keep examples up to date if they use for example timestamps
that should be in the future to be valid.
Add description to application
Often we would like to provide short description of the application,
which version it has. We can use the package openapi3
to update OpenApi
directly. But also there is a helper type for most often used fields:
-- | Default info that is often added to OpenApi schema
data DefaultInfo = DefaultInfo
{ title :: Text
, description :: Text
, version :: Text
}
addDefaultInfo :: DefaultInfo -> OpenApi -> OpenApi
We can set title, description and version for the application. Here is an example:
setSwagger :: Server IO -> Server IO
setSwagger = withSwagger config
where
config =
(def :: SwaggerConfig IO)
{ mapSchema = pure . addDefaultInfo info
}
info =
def
{ title = "Weather forecast"
, description =
"JSON API example for mig library which shows how to forecast weather to authorized users"
, version = "0.1.0"
}
Describe the routes
Often we would like to add some useful documentation on the routes. We can do it with the functions:
-- | Sets description of the route
setDescription :: Text -> Server m -> Server m
-- | Sets summary of the route
setSummary :: Text -> Server m -> Server m
-- | Adds OpenApi tag to the route
addTag :: Text -> Server m -> Server m
We can apply those functions at definition of the route. Also we can describe the inputs for the route:
{-| Appends descriptiton for the inputs. It passes pairs for
@(input-name, input-description)@. Special name request-body
is dedicated to request body input nd raw-input is dedicated
to raw input
-}
describeInputs :: [(Text, Text)] -> Server m -> Server m
It takes a map from input parameter name to description. There is special name "request-body"
for the request body input.
An example:
server = "calculator" /.
mconcat
[ describeAdd $ "add" /. add
, describeMul $ "mul" /. mull
]
where
describeAdd = setDescription "Performs addition" . describeArgs
describeMul = setDescription "Performs multiplication" . describeArgs
describeArgs = describeInputs [("a", "first argument"), ("b", "second argument")]
add, mul :: Capture "a" Int -> Capture "b" Int -> Get (Resp Int)
Summary
In this chapter we have learned how to tweak our swagger servers and make them more user-friendly.