openapi-hs-5.0.0: MIGRATION_4_TO_5.md
# Migrating from `openapi-hs` 4 to 5
`openapi-hs` 5.0.0 removes its `optics` interface and the external
`insert-ordered-containers` dependency. The `lens` interface remains the supported way to read
and update OpenAPI records. This guide covers the source changes needed by downstream users.
## Replace optics labels with lens accessors
Version 4 generated both overloaded `optics` labels and ordinary `lens` accessors. Version 5
removes `Data.OpenApi.Optics`, so remove that import and use the accessors re-exported by
`Data.OpenApi`:
```haskell
-- Before (openapi-hs 4)
{-# LANGUAGE OverloadedLabels #-}
import Data.OpenApi
import Data.OpenApi.Optics ()
import Optics.Core
schemaType = view #type schema
updated = set (#schema % #type) (Just (OpenApiTypeSingle OpenApiString)) namedSchema
```
```haskell
-- After (openapi-hs 5)
import Control.Lens
import Data.OpenApi
schemaType = view type_ schema
updated = set (schema . type_) (Just (OpenApiTypeSingle OpenApiString)) namedSchema
```
`lens` accessors compose with ordinary `(.)`; the removed `optics` labels composed with `%`.
Fields whose ordinary names collide with Haskell keywords, Prelude names, or other accessors
have a trailing underscore. Common migrations are `#type` to `type_`, `#default` to `default_`,
`#maximum` to `maximum_`, and `#minimum` to `minimum_`. Other examples include `enum_`,
`const_`, `if_`, `then_`, `else_`, `contains_`, and `id_`.
Remove `optics-core` and `optics-th` from your own dependencies only when your code has no
independent use for them.
## Use the compat insertion-ordered map
OpenAPI map fields use the public compat map from this package. Change direct imports from the
external package:
```haskell
-- Before
import Data.HashMap.Strict.InsOrd qualified as InsOrdHashMap
```
```haskell
-- After
import Data.HashMap.Strict.InsOrd.Compat qualified as InsOrdHashMap
```
Functions such as `empty`, `fromList`, `insert`, `insertWith`, `unionWith`, and `lookup` retain
the same names. The compat map intentionally compares equality without considering insertion
order and encodes string-like keys as a JSON object in insertion order.
## Use the compat insertion-ordered set
OpenAPI tag fields now use a set exposed directly by `openapi-hs`:
```haskell
-- Before
import Data.HashSet.InsOrd qualified as InsOrdHashSet
```
```haskell
-- After
import Data.HashSet.InsOrd.Compat qualified as InsOrdHashSet
```
The set keeps its non-optics public instances, including `NFData`, `NFData1`, `ToJSON`,
`FromJSON`, and the `lens` `Ixed`, `At`, and `Contains` instances.
Remove `insert-ordered-containers` from your own dependencies only when no other part of your
application still imports it independently.
## Compiler and lens bounds
Version 5 requires `lens >=5.3.3 && <5.4`. The lower bound is verified with GHC 9.12. On GHC
9.14, the solver selects `lens-5.3.6`, the first release in this range that permits GHC 9.14's
`template-haskell` version.