{"id":13687578,"url":"https://github.com/mrkkrp/modern-uri","last_synced_at":"2025-04-09T14:11:32.279Z","repository":{"id":26300457,"uuid":"107874019","full_name":"mrkkrp/modern-uri","owner":"mrkkrp","description":"Modern library for working with URIs","archived":false,"fork":false,"pushed_at":"2023-10-22T10:54:49.000Z","size":246,"stargazers_count":68,"open_issues_count":5,"forks_count":18,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-05-08T20:24:46.715Z","etag":null,"topics":["haskell","uri"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrkkrp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-10-22T14:39:18.000Z","updated_at":"2024-04-17T21:01:34.000Z","dependencies_parsed_at":"2023-09-22T01:48:57.040Z","dependency_job_id":"2f63895b-7226-4bb0-bea5-9a8cfa9bb26a","html_url":"https://github.com/mrkkrp/modern-uri","commit_stats":{"total_commits":192,"total_committers":12,"mean_commits":16.0,"dds":0.078125,"last_synced_commit":"b66ad68dd07bd954ae3eac968a8ce7ceb30bab72"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fmodern-uri","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fmodern-uri/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fmodern-uri/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fmodern-uri/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrkkrp","download_url":"https://codeload.github.com/mrkkrp/modern-uri/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248054196,"owners_count":21039952,"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":["haskell","uri"],"created_at":"2024-08-02T15:00:56.961Z","updated_at":"2025-04-09T14:11:32.257Z","avatar_url":"https://github.com/mrkkrp.png","language":"Haskell","funding_links":[],"categories":["Haskell"],"sub_categories":[],"readme":"# Modern URI\n\n[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)\n[![Hackage](https://img.shields.io/hackage/v/modern-uri.svg?style=flat)](https://hackage.haskell.org/package/modern-uri)\n[![Stackage Nightly](http://stackage.org/package/modern-uri/badge/nightly)](http://stackage.org/nightly/package/modern-uri)\n[![Stackage LTS](http://stackage.org/package/modern-uri/badge/lts)](http://stackage.org/lts/package/modern-uri)\n[![CI](https://github.com/mrkkrp/modern-uri/actions/workflows/ci.yaml/badge.svg)](https://github.com/mrkkrp/modern-uri/actions/workflows/ci.yaml)\n\nThis is a modern library for working with URIs in Haskell as per RFC 3986:\n\nhttps://tools.ietf.org/html/rfc3986\n\n## Features\n\nThe `modern-uri` package features:\n\n* Correct by construction `URI` data type. The correctness is ensured by\n  making sure that every sub-component of the `URI` record cannot be\n  invalid.\n* Textual components in the `URI` data type are represented as `Text` rather\n  than `ByteString`, because they are percent-decoded and so they can\n  contain characters outside of ASCII range (i.e. Unicode). This allows for\n  easier manipulation of `URI`s, while encoding and decoding headaches are\n  handled by the parsers and renders for you.\n* Absolute and relative URIs differ only by the scheme component: if it's\n  `Nothing`, then the URI is relative, otherwise it's absolute.\n* A Megaparsec parser that can be used as a standalone smart constructor for\n  the `URI` data type (see `mkURI`) as well as seamlessly integrated into a\n  bigger Megaparsec parser that consumes a strict `Text` (see `parser`) or\n  strict `ByteString` (see `parserBs`).\n* The parser performs some normalization, for example it collapses\n  consecutive slashes. Some smart constructors such as `mkScheme` and\n  `mkHost` also perform normalization. So in a sense URIs are also\n  “normalized by construction” to some extent.\n* Fast rendering to strict `Text` and `ByteString` as well as to their\n  respective `Builder` types and to `String`/`ShowS`.\n* Extensive set of lensy helpers for easier manipulation of the nested data\n  types (see `Text.URI.Lens`).\n* Quasi-quoters for compile-time construction of the `URI` data type and\n  refined text types (see `Text.URI.QQ`).\n\n## Quick start\n\nThe `modern-uri` package serves three main purposes:\n\n* Construction of the `URI` data type.\n* Inspection and manipulation of the `URI` data type (in the sense of\n  changing its parts).\n* Rendering of `URI`s.\n\nLet's walk through every operation quickly.\n\n### Construction of `URI`s\n\nThere are four ways to create a `URI` value. First off, one could assemble\nit manually like so:\n\n```haskell\nλ\u003e :set -XOverloadedStrings\nλ\u003e import qualified Text.URI as URI\nλ\u003e scheme \u003c- URI.mkScheme \"https\"\nλ\u003e scheme\n\"https\"\nλ\u003e host \u003c- URI.mkHost \"markkarpov.com\"\nλ\u003e host\n\"markkarpov.com\"\nλ\u003e let uri = URI.URI (Just scheme) (Right (URI.Authority Nothing host Nothing)) Nothing [] Nothing\nλ\u003e uri\nURI\n  { uriScheme = Just \"https\",\n    uriAuthority =\n      Right\n        ( Authority\n            { authUserInfo = Nothing,\n              authHost = \"markkarpov.com\",\n              authPort = Nothing\n            }\n        ),\n    uriPath = Nothing,\n    uriQuery = [],\n    uriFragment = Nothing\n  }\n```\n\nIn this library we use quite a few refined text values. They only can be\nconstructed by using smart constructors like `mkScheme :: MonadThrow m =\u003e\nText -\u003e m (RText 'Scheme)`. For example, if argument to `mkScheme` is not a\nvalid scheme, an exception will be thrown. Note that monads such as `Maybe`\nare also instances of the `MonadThrow` type class, and so the smart\nconstructors can be used in pure environment as well.\n\nThere is a smart constructor that can make an entire `URI` too, it's called\n(unsurprisingly) `mkURI`:\n\n```haskell\nλ\u003e uri \u003c- URI.mkURI \"https://markkarpov.com\"\nλ\u003e uri\nURI\n  { uriScheme = Just \"https\",\n    uriAuthority =\n      Right\n        ( Authority\n            { authUserInfo = Nothing,\n              authHost = \"markkarpov.com\",\n              authPort = Nothing\n            }\n        ),\n    uriPath = Nothing,\n    uriQuery = [],\n    uriFragment = Nothing\n  }\n```\n\nIf the argument of `mkURI` is not a valid URI, then an exception will be\nthrown. The exception will contain full context and the actual parse error.\n\nIf some refined text value or `URI` is known statically at compile time, we\ncan use Template Haskell, namely the “quasi quotes” feature. To do so import\nthe `Text.URI.QQ` module and enable the `QuasiQuotes` language extension,\nlike so:\n\n```haskell\nλ\u003e :set -XQuasiQuotes\nλ\u003e import qualified Text.URI.QQ as QQ\nλ\u003e let uri = [QQ.uri|https://markkarpov.com|]\nλ\u003e uri\nURI\n  { uriScheme = Just \"https\",\n    uriAuthority =\n      Right\n        ( Authority\n            { authUserInfo = Nothing,\n              authHost = \"markkarpov.com\",\n              authPort = Nothing\n            }\n        ),\n    uriPath = Nothing,\n    uriQuery = [],\n    uriFragment = Nothing\n  }\n```\n\nNote how the value returned by the `url` quasi quote is pure, its\nconstruction cannot fail because when there is an invalid URI inside the\nquote it's a compilation error. The `Text.URI.QQ` module has quasi-quoters\nfor scheme, host, and other components.\n\nFinally, the package provides two Megaparsec parsers: `parser` and\n`parserBs`. The first works on strict `Text`, while the other one works on\nstrict `ByteString`s. You can use the parsers in a bigger Megaparsec parser\nto parse `URI`s.\n\n### Inspection and manipulation\n\nAlthough one could use record syntax directly, possibly with language\nextensions like `RecordWildcards`, the best way to inspect and edit parts of\n`URI` is with lenses. The lenses can be found in the `Text.URI.Lens` module.\nIf you have never used the\n[`lens`](https://hackage.haskell.org/package/lens) library, you could\nprobably start by reading/watching materials suggested in the library\ndescription on Hackage.\n\nHere are some examples, just to show off what you can do:\n\n```haskell\nλ\u003e import Text.URI.Lens\nλ\u003e uri \u003c- URI.mkURI \"https://example.com/some/path?foo=bar\u0026baz=quux\u0026foo=foo\"\nλ\u003e uri ^. uriScheme\nJust \"https\"\nλ\u003e uri ^? uriAuthority . _Right . authHost\nJust \"example.com\"\nλ\u003e uri ^. isPathAbsolute\nTrue\nλ\u003e uri ^. uriPath\n[\"some\",\"path\"]\nλ\u003e k \u003c- URI.mkQueryKey \"foo\"\nλ\u003e uri ^.. uriQuery . queryParam k\n[\"bar\",\"foo\"]\n-- etc.\n```\n\n### Rendering\n\nRendering turns a `URI` into a sequence of bytes or characters. Currently\nthe following options are available:\n\n* `render` for rendering to strict `Text`.\n* `render'` for rendering to text `Builder`. It's possible to turn that into\n  lazy `Text` by using the `toLazyText` function from\n  `Data.Text.Lazy.Builder`.\n* `renderBs` for rendering to strict `ByteString`.\n* `renderBs'` for rendering to byte string `Builder`. Similarly it's\n  possible to get a lazy `ByteString` from that by using the\n  `toLazyByteString` function from `Data.ByteString.Builder`.\n* `renderStr` can be used to render to `String`. Sometimes it's handy. The\n  render uses difference lists internally so it's not that slow, but in\n  general I'd advise avoiding `String`s.\n* `renderStr'` returns `ShowS`, which is just a synonym for `String -\u003e\n  String`—a function that prepends the result of rendering to a given\n  `String`. This is useful when the `URI` you want to render is a part of a\n  bigger output, just like with the builders mentioned above.\n\nExamples:\n\n```haskell\nλ\u003e uri \u003c- mkURI \"https://markkarpov.com/posts.html\"\nλ\u003e render uri\n\"https://markkarpov.com/posts.html\"\nλ\u003e renderBs uri\n\"https://markkarpov.com/posts.html\"\nλ\u003e renderStr uri\n\"https://markkarpov.com/posts.html\"\n-- etc.\n```\n\n## Contribution\n\nIssues, bugs, and questions may be reported in [the GitHub issue tracker for\nthis project](https://github.com/mrkkrp/modern-uri/issues).\n\nPull requests are also welcome.\n\n## License\n\nCopyright © 2017–present Mark Karpov\n\nDistributed under BSD 3 clause license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrkkrp%2Fmodern-uri","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrkkrp%2Fmodern-uri","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrkkrp%2Fmodern-uri/lists"}