{"id":21517580,"url":"https://github.com/tek/polysemy-http","last_synced_at":"2025-04-09T21:42:30.092Z","repository":{"id":45076390,"uuid":"290232362","full_name":"tek/polysemy-http","owner":"tek","description":"polysemy effect for http-client","archived":false,"fork":false,"pushed_at":"2023-09-23T17:27:19.000Z","size":265,"stargazers_count":10,"open_issues_count":1,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-04-25T08:02:25.674Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tek.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-25T14:08:16.000Z","updated_at":"2023-09-23T17:27:23.000Z","dependencies_parsed_at":"2024-11-24T00:43:05.773Z","dependency_job_id":"dafb9fd3-84ed-445f-a053-a923b0e5b45f","html_url":"https://github.com/tek/polysemy-http","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tek%2Fpolysemy-http","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tek%2Fpolysemy-http/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tek%2Fpolysemy-http/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tek%2Fpolysemy-http/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tek","download_url":"https://codeload.github.com/tek/polysemy-http/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248118937,"owners_count":21050747,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-24T00:43:03.110Z","updated_at":"2025-04-09T21:42:30.040Z","avatar_url":"https://github.com/tek.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# About\n\nThis Haskell library provides a [Polysemy] effect for running HTTP requests\nwith [http-client].\n\n# Example\n\n```haskell\nimport Polysemy (runM)\nimport Polysemy.Resource (resourceToIO)\nimport qualified Polysemy.Http as Http\nimport Polysemy.Http (interpretHttpNative)\nimport Polysemy.Log (interpretLogStdout')\n\nmain :: IO ()\nmain = do\n  result \u003c- runM $\n    resourceToIO $\n    interpretLogStdout' $\n    interpretHttpNative $\n    Http.request (Http.get \"hackage.haskell.org\" \"package/polysemy-http\")\n  print result\n```\n\n# API\n\n## Request\n\nThe effect constructor `Http.request` takes an argument of type\n`Polysemy.Http.Data.Request.Request`:\n\n```haskell\ndata Request =\n  Request {\n    _method :: Method,\n    _host :: Host,\n    _port :: Maybe Port,\n    _tls :: Tls,\n    _path :: Path,\n    _headers :: [(HeaderName, HeaderValue)],\n    _cookies :: CookieJar,\n    _query :: [(QueryKey, Maybe QueryValue)],\n    _body :: Body\n  }\n```\n\nMost of these fields are just newtypes, except for `Method`, which is an enum:\n\n```haskell\ndata Method =\n  Get | Post | ... | Custom Text\n```\n\nIt has an `IsString` instance, so you can just write `\"GET\"` or `\"delete\"`.\n\nAll `Text` newtypes have `IsString` as well, and they will be converted to\n`CI` and `ByteString` if needed when they are passed to [http-client].\n`Body` is an `LByteString` newtype since that is what [aeson] typically\nproduces.\nThe port field is intended for nonstandard ports – if it is `Nothing`, the port\nwill be determined from `tls`.\n\n## Response\n\n`Http.request` returns `Either HttpError (Response LByteString)`, with\n`Polysemy.Http.Data.Response.Response` looking like this:\n\n```haskell\ndata Response b =\n  Response {\n    _status :: Status,\n    _body :: b,\n    _headers :: [Header],\n    _cookies :: CookieJar\n  }\n\ndata Header =\n  Header {\n    name :: HeaderName,\n    value :: HeaderValue\n  }\n```\n\n`Status` is from `http-types`, because it has some helpful combinators. Its\n`Header` is just an alias, so this newtype is provided.\nThe parameter `b` is intended to allow you to write interpreters that produce\n`Text` or something else, for example for [#testing].\n\n# Streaming\n\nThe higher-order constructor `Http.stream` opens and closes the request\nmanually and passes the response to a handler function.\nThe function `streamResponse` provides a simpler interface for this mechanism\nthat runs a loop that passes individual chunks produced by [http-client] to\na callback handler of type `∀ x . StreamEvent r c h x -\u003e Sem r x` that should\nlook like this:\n\n```haskell\nhandle ::\n  StreamEvent Double (IO ByteString) Int a -\u003e\n  Sem r a\nhandle = \\case\n  StreamEvent.Acquire (Response status body headers) -\u003e\n    pure 1\n  StreamEvent.Chunk handle (StreamChunk c) -\u003e\n    pure ()\n  StreamEvent.Result (Response status body headers) handle -\u003e\n    pure 5.5\n  StreamEvent.Release handle -\u003e\n    pure ()\n\nrun :: Sem r Double\nrun =\n  Http.streamResponse (Request.get \"host.com\" \"path/to/file\") handle\n```\n\nIf you were e.g. to write the data to disk, you would open the file in the\n`Acquire` block, write the `ByteString` `c` in `Chunk`, and close the file in\n`Release`.\nThe parameter `h` could then be `Handle`.\nThe callbacks are wrapped in `Resource.bracket`, so `Release` is guaranteed to\nbe called (as much as `Resource` is reliable).\nThe `Result` block is called when the transfer is complete; its returned value\nis finally returned from `streamHandler.`\nThe `handle` is an arbitrary identifier that the user can return from\n`Acquire`; it is not needed for the machinery and may be `()`.\n\n# Entity\n\nThe library also provides effects for request and response entity de/encoding,\n`EntityDecode d m a` and `EntityEncode d m a`, making it possible to abstract\nover json implementations or content types using interpreters.\nSince the effects are parameterized by the codec data type, one interpreter per\ntype must be used.\n\nImplementations for [aeson] are available as `interpretEntityDecodeAeson` and\n`interpretEntityEncodeAeson`:\n\n```haskell\nimport Polysemy (run)\nimport qualified Polysemy.Http as Http\nimport Polysemy.Http (interpretEntityDecodeAeson)\n\ndata Dat { a :: Maybe Int, b :: Text }\nderiving (Show, FromJSON)\n\nmain :: IO\nmain =\n  print $ run $ interpretEntityDecodeAeson $ Http.decode \"{ \\\"b\\\": \\\"hello\\\" }\"\n```\n\nThere is not integration with the `Http` effect for this.\n\n# Testing\n\nPolysemy makes it very easy to switch the native interpreter for a mock, and\nthere is a convenience interpreter named `interpretHttpPure` that allows you\nto specify a list of responses and chunks that should be produced:\n\n```haskell\nmain :: IO ()\nmain = do\n  result \u003c- runM $\n    resourceToIO $\n    interpretLogStdout' $\n    interpretHttpPure [Response (toEnum 200) \"foo\" []] [] $\n    Http.request (Http.get \"hackage.haskell.org\" \"package/polysemy-http\")\n  print result\n```\n\n[Polysemy]: https://hackage.haskell.org/package/polysemy\n[http-client]: https://hackage.haskell.org/package/http-client\n[http-types]: https://hackage.haskell.org/package/http-types\n[aeson]: https://hackage.haskell.org/package/aeson\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftek%2Fpolysemy-http","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftek%2Fpolysemy-http","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftek%2Fpolysemy-http/lists"}