I assume your API can be expressed as this function signature:
parseDataFromHTMLResource :: Resource -> HTMLRaw -> Maybe Data
...and assuming we validate the HTML:
validateHTML :: HTMLRaw -> Maybe HTML
I think your question relies on the separation of 'Resource', as a domain separation like right below will probably create a lot of duplication (since any resource is free to structure their HTML within the standard however they want):
parseDataFromGoogleHTML :: HTML -> Maybe Data
parseDataFromGithubHTML :: HTML -> Maybe Data
parseDataFrom...
Perhaps you can reduce the duplication by converging to different fingerprinted resources. So a HTML resource, fingerprinted by style, will then guarantee your data:
data HTMLFingerprinted =
HTMLStyleGoogle
| HTMLStyleGithub
| ...
htmlFingerprintedFromHTML :: HTML -> Maybe HTMLFingerprinted -- So the Maybe will be here
parseDataFromHTMLFingerprinted :: HTMLFingerprinted -> Data -- ...not here
(Note that this may be what the parent means. It helps solving "
For me it's usually, "Oh crap that thing I changed I had to change here and here too, whoops its good now... Wait no I also had to change it here... and here... now that we're done with that we should be fine... DAMMIT!"" with "
I just create this abstraction".)
I would say if you're able to implement the function 'htmlFingerprintedFromHTML', you deserve the abstraction and thus DRY the codebase on the fly. And this "no pain no gain" mantra is what I personally really like on a 'functional core'. Code stays only duplicated where absolutely needed until you find a solution for the abstraction.
...and I guess implementations of fingerprinting HTML may vary a lot.