Для этого вам придется конвертировать ваши Entity
к Value
вручную, а затем использовать функции unordered-containers:Data.HashMap.Strict
вставить ключ "_links"
, а затем построить Value
из него снова. Используя совместимый пакет объектива для aeson
, вероятно, может упростить это совсем немного, хотя:
buildEntityWithLink :: Entity -> Text -> Maybe Value
buildEntityWithLink entity renderedUrl = case toJSON entity of
Object obj ->
let links = object ["self" .= renderedUrl]
entityWithLink = HashMap.insert "_links" links obj
in Just (Object entityWithLink)
_ -> Nothing
(я предполагаю, что renderedUrl
имеет тип Text
, изменить при необходимости)
Тогда вы можете просто передать в ваш Entity
и renderedUrl
, чтобы получить новый Value
с ключом "_links"
. Я использовал Maybe
здесь для защиты от случая, когда toJSON :: Entity -> Value
не возвращает Value
с помощью конструктора Object
. Это защитит вас в будущем, если вы измените тип Entity
и как он преобразуется в JSON, но забудьте обновить всю свою кодовую базу, чтобы отразить это изменение.
EDIT: Если вы должны были использовать lens-aeson
Вы могли бы написать это так, хотя это требует изменения порядка аргументов только для опрятности:
buildEntityWithLink :: Text -> Entity -> Value
buildEntityWithLink renderedUrl = (
over _Object $
HashMap.insert "_links" $
object ["self" .= renderedUrl]
) . toJSON
Это фактически позволяет отказаться от Maybe
, вы хотите, чтобы в любом случае, так как способ работы линз означает, что если Object
не является верхним уровнем, тогда возвращается исходное значение, поэтому buildEntityWithLink "testlink" ([] :: [Entity])
будет просто возвращать то же самое, что и toJSON ([] :: [Entity])
, а именно пустой Array
. toJSON
должен находиться снаружи от объектива, потому что для составления с _Object
он должен быть в качестве сеттера, и toJSON
не может быть легко превращен в сеттер. Вместо этого мы просто предварительно обработаем наш Entity
в Value
, а затем подайте его в выражение объектива. Я добавил пробелы, где я выровнял аргументы для каждой функции, делает ее более читаемой ИМО, но это все технически 1 строка кода. Полезной особенностью этой реализации является то, что теперь легко отключить сигнатуру типа до ToJSON a => Text -> a -> Value
, поэтому вы можете добавить _links
в любой тип, который вы хотите.
Спасибо за это. «Использование пакета, совместимого с объективом для aeson, возможно, упростило бы это совсем немного», - у вас есть пример для этого, я не мог найти? – amitaibu
@amitaibu Проверить мои изменения – bheklilr