Skip to content

Commit f8095f6

Browse files
Avoid WithStatus when recursing into Verbs
1 parent 97b2fd0 commit f8095f6

File tree

2 files changed

+49
-32
lines changed

2 files changed

+49
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ Unreleased
33

44
* The `HasOpenApi` instance that recurses through `UVerb` responses no
55
longer demands `ToSchema NoContent`.
6+
- `instance ToSchema (WithStatus s a)` has been removed, as the
7+
`WithStatus` is now unwrapped when recursing into a `Verb`.
68
* Do not count `NoContent` as a body type if it appears in `Headers
79
hdrs NoContent`.
810

src/Servant/OpenApi/Internal.hs

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -206,38 +206,53 @@ instance
206206
toOpenApi _ =
207207
toOpenApi (Proxy :: Proxy (Verb method (StatusOf a) cs a))
208208
`combineSwagger` toOpenApi (Proxy :: Proxy (UVerb method cs as))
209-
where
210-
-- workaround for https://github.com/GetShopTV/swagger2/issues/218
211-
combinePathItem :: PathItem -> PathItem -> PathItem
212-
combinePathItem s t = PathItem
213-
{ _pathItemGet = _pathItemGet s <> _pathItemGet t
214-
, _pathItemPut = _pathItemPut s <> _pathItemPut t
215-
, _pathItemPost = _pathItemPost s <> _pathItemPost t
216-
, _pathItemDelete = _pathItemDelete s <> _pathItemDelete t
217-
, _pathItemOptions = _pathItemOptions s <> _pathItemOptions t
218-
, _pathItemHead = _pathItemHead s <> _pathItemHead t
219-
, _pathItemPatch = _pathItemPatch s <> _pathItemPatch t
220-
, _pathItemTrace = _pathItemTrace s <> _pathItemTrace t
221-
, _pathItemParameters = _pathItemParameters s <> _pathItemParameters t
222-
, _pathItemSummary = _pathItemSummary s <|> _pathItemSummary t
223-
, _pathItemDescription = _pathItemDescription s <|> _pathItemDescription t
224-
, _pathItemServers = _pathItemServers s <> _pathItemServers t
225-
}
226-
227-
combineSwagger :: OpenApi -> OpenApi -> OpenApi
228-
combineSwagger s t = OpenApi
229-
{ _openApiOpenapi = _openApiOpenapi s <> _openApiOpenapi t
230-
, _openApiInfo = _openApiInfo s <> _openApiInfo t
231-
, _openApiServers = _openApiServers s <> _openApiServers t
232-
, _openApiPaths = InsOrdHashMap.unionWith combinePathItem (_openApiPaths s) (_openApiPaths t)
233-
, _openApiComponents = _openApiComponents s <> _openApiComponents t
234-
, _openApiSecurity = _openApiSecurity s <> _openApiSecurity t
235-
, _openApiTags = _openApiTags s <> _openApiTags t
236-
, _openApiExternalDocs = _openApiExternalDocs s <|> _openApiExternalDocs t
237-
}
238-
239-
instance (Typeable (WithStatus s a), ToSchema a) => ToSchema (WithStatus s a) where
240-
declareNamedSchema _ = declareNamedSchema (Proxy :: Proxy a)
209+
210+
-- | Although the instance this overlaps correctly sets the status code
211+
-- for a @WithStatus n a@ entry, it also cause GHC to try and solve
212+
-- @'HasOpenApi' (Verb method (StatusOf (WithStatus n a)) cs (WithStatus n a))@.
213+
-- In most cases, this works fine, but it breaks down if @a ~ NoContent@ by
214+
-- trying to satisfy @ToSchema NoContent@.
215+
--
216+
-- Because 'WithStatus' inside a 'Verb' is nonsensical, we handle it
217+
-- explicitly before recursing into the @HasOpenApi (Verb method n cs a)@
218+
-- instance.
219+
instance
220+
( HasOpenApi (Verb method n cs a),
221+
HasOpenApi (UVerb method cs as)
222+
) => HasOpenApi (UVerb method cs (WithStatus n a ': as))
223+
where
224+
toOpenApi _ =
225+
toOpenApi (Proxy :: Proxy (Verb method n cs a))
226+
`combineSwagger` toOpenApi (Proxy :: Proxy (UVerb method cs as))
227+
228+
-- Workaround for https://github.com/GetShopTV/swagger2/issues/218
229+
combineSwagger :: OpenApi -> OpenApi -> OpenApi
230+
combineSwagger s1 s2 = OpenApi
231+
{ _openApiOpenapi = _openApiOpenapi s1 <> _openApiOpenapi s2
232+
, _openApiInfo = _openApiInfo s1 <> _openApiInfo s2
233+
, _openApiServers = _openApiServers s1 <> _openApiServers s2
234+
, _openApiPaths = InsOrdHashMap.unionWith combinePathItem (_openApiPaths s1) (_openApiPaths s2)
235+
, _openApiComponents = _openApiComponents s1 <> _openApiComponents s2
236+
, _openApiSecurity = _openApiSecurity s1 <> _openApiSecurity s2
237+
, _openApiTags = _openApiTags s1 <> _openApiTags s2
238+
, _openApiExternalDocs = _openApiExternalDocs s1 <|> _openApiExternalDocs s2
239+
}
240+
where
241+
combinePathItem :: PathItem -> PathItem -> PathItem
242+
combinePathItem p1 p2 = PathItem
243+
{ _pathItemGet = _pathItemGet p1 <> _pathItemGet p2
244+
, _pathItemPut = _pathItemPut p1 <> _pathItemPut p2
245+
, _pathItemPost = _pathItemPost p1 <> _pathItemPost p2
246+
, _pathItemDelete = _pathItemDelete p1 <> _pathItemDelete p2
247+
, _pathItemOptions = _pathItemOptions p1 <> _pathItemOptions p2
248+
, _pathItemHead = _pathItemHead p1 <> _pathItemHead p2
249+
, _pathItemPatch = _pathItemPatch p1 <> _pathItemPatch p2
250+
, _pathItemTrace = _pathItemTrace p1 <> _pathItemTrace p2
251+
, _pathItemParameters = _pathItemParameters p1 <> _pathItemParameters p2
252+
, _pathItemSummary = _pathItemSummary p1 <|> _pathItemSummary p2
253+
, _pathItemDescription = _pathItemDescription p1 <|> _pathItemDescription p2
254+
, _pathItemServers = _pathItemServers p1 <> _pathItemServers p2
255+
}
241256
#endif
242257

243258
instance {-# OVERLAPPABLE #-} (ToSchema a, AllAccept cs, KnownNat status, OpenApiMethod method) => HasOpenApi (Verb method status cs a) where

0 commit comments

Comments
 (0)