5 ms·
The thing is, I needed a very specific kind of output for the JSON request I needed to make, and from messing around with lenses I couldn't get it work out. I d
by square_usual 5y ago
The thing is, I needed a very specific kind of output for the JSON request I needed to make, and from messing around with lenses I couldn't get it work out. I don't remember what the exact usecase was, but for a hypothetical example, consider an awful POST endpoint that needs the authorization token to be in the json body. So you would have a request like:
{
"page": 1,
"token": "eyJ..."
}
But ideally, you'd abstract out the auth stuff and put it in a central location which injects it into all requests that need it, eg. if you're using axios you'd add an interceptor for it. We couldn't find a way to do this without making the request into a Dictionary<string, obj>. It's entirely possible this could work with lenses, but from what I looked at I couldn't make it happen.
As an aside, I chuckled at the 'Did they fail you, too?'; it made me wonder how lenses could've failed you.
- solomonb 5y agoLenses are definitely not necessary to do what you want here. In haskell, you typically keep the JSON data to the very periphery of your program. You would probably have some Request with a ToJSON instance and Token types such as: data Request = Request { url :: URI , method :: Method , headers :: [Header] , body :: ByteString ... } instance ToJSON Request where toJSON = ... newtype Token = Token ByteString Then you might write a function to add the token header: applyAuthToken :: Token -> Request -> Request applyAuthToken (Token tok) req = req { headers = ("token", tok) : req headers } Or if you really wanted to use a lens you could do: headersL :: Lens' Request [Header] headersL = lens headers (\req hdrs -> req { headers = hdrs }) applyAuthToken :: Token -> Request -> Request applyAuthToken (Token tok) req = over headersL ("token", tok) :) req Then you call applyAuthToken right before serializing your Request type to a JSON ByteString. edit: sorry I see that you wanted the auth token in the body not the headers. Its the exact same concept but you would make the `body` field in `Request` into some other specific type with a ToJSON instance and a slightly different `applyAuthToken` function.
- lmm 5y ago> But ideally, you'd abstract out the auth stuff and put it in a central location which injects it into all requests that need it, eg. if you're using axios you'd add an interceptor for it. We couldn't find a way to do this without making the request into a Dictionary<string, obj>. I do this kind of thing in Scala using Shapeless records sometimes. You can work pretty easily with types like "this case class, plus a field called token of type String", though writing those types down is a pain (they're basically recursive hlists of fields tagged with singleton types for their names). Apparently GHC.Generic is the closest Haskell equivalent?
- Eugeleo 5y agoNot that it matters now, but I’ve recently learned about generic-data-surgery [1], a library that let’s you take a record X and return a record X with an added field Y. Pretty cool stuff, considering it’s all strongly typed. You would need to do the JSON serialisation _after_ the addToken step, but that shouldn’t be a problem. [1]: https://hackage.haskell.org/package/generic-data-surgery-0.3.0.0/docs/Generic-Data-Surgery.html https://hackage.haskell.org/package/generic-data-surgery-0.3...