{"id":31808351,"url":"https://github.com/3kyro/servant-benchmark","last_synced_at":"2025-10-11T04:42:27.208Z","repository":{"id":52226904,"uuid":"356056822","full_name":"3kyro/servant-benchmark","owner":"3kyro","description":"Generate benchmark files from Servant APIs","archived":false,"fork":false,"pushed_at":"2021-10-11T11:42:46.000Z","size":97,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-28T17:55:57.205Z","etag":null,"topics":["benchmark","servant"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/servant-benchmark","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/3kyro.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-08T21:50:24.000Z","updated_at":"2021-10-11T11:42:50.000Z","dependencies_parsed_at":"2022-08-20T23:10:10.904Z","dependency_job_id":null,"html_url":"https://github.com/3kyro/servant-benchmark","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/3kyro/servant-benchmark","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3kyro%2Fservant-benchmark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3kyro%2Fservant-benchmark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3kyro%2Fservant-benchmark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3kyro%2Fservant-benchmark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/3kyro","download_url":"https://codeload.github.com/3kyro/servant-benchmark/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3kyro%2Fservant-benchmark/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279006242,"owners_count":26084061,"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","status":"online","status_checked_at":"2025-10-11T02:00:06.511Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["benchmark","servant"],"created_at":"2025-10-11T04:42:19.474Z","updated_at":"2025-10-11T04:42:27.203Z","avatar_url":"https://github.com/3kyro.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# servant-benchmark\n\nA library for producing random request data from *Servant* APIs. \n\n## Building a `Generator`\n\nThe `Generator` type must closely follow the structure of the *Servant* API. \n\n* Different endpoints are combined with the `:|:` operator\n* Different generators are combined with the `:\u003e:` operator\n* Every endpoint must end with a  `(Text, Word)` tuple consisting of the endpoint name and its corresponding weight.\n  Endpoint names are only used for additional information passed to the benchmark implementations\n  and do not have to follow specific rules. That being said, generators for extensive APIs can get\n  rather big and hard to read, so providing sensible naming could be very beneficial.  \n* The weight of an endpoint specifies the number of instances per testing run\n  of the API. Endpoints with 0 weight will be ignored.\n* For every API combinator expecting a request value, a `Gen a` random value generator from the\n  [QuickCheck](https://hackage.haskell.org/package/QuickCheck) package must be provided. \n  The following combinators require a value generator:\n    * `ReqBody`\n    * `QueryParams`\n    * `Capture`\n    * `CaptureAll`\n    * `Header`\n    * `Fragment`\n* For the `BasicAuth` combinator, see the dedicated section below \n\nAs an example, the following is a valid `Generator` for a contrived servant API\n\n````haskell\n{-# LANGUAGE OverloadedStrings #-}\n{-# LANGUAGE DataKinds #-}\n{-# LANGUAGE TypeOperators #-}\n\ntype API = \n    \"books\" :\u003e Get '[JSON] [Book]\n    :\u003c|\u003e \"view-my-referer\" :\u003e Header \"from\" Referer :\u003e Get '[JSON] Referer\n    :\u003c|\u003e \"users\" :\u003e Capture \"userId\" Integer :\u003e ReqBody '[JSON] User :\u003e Put '[JSON] User\n    :\u003c|\u003e \"post\" :\u003e QueryParam \"segments\" Text :\u003e Get '[JSON] Post\n    :\u003c|\u003e Raw\n\ngenerator :: Generator API\nlet generator =\n    (\"books\", 1)\n    :|: arbitrary :\u003e: (\"referer\", 2)\n    :|: pure 1001 :\u003e: arbitrary :\u003e: (\"users endpoint\", 2)\n    :|: elements [\"title\", \"contents\", \"post\"] :\u003e: (\"post\", 4)\n    :|: (\"raw\", 0)\n````\n\nThe first endpoint \"books\" does not require request data and so only the name / weight tuple is\nprovided.\n\nThe \"view-my-referer\" endpoint requires a \"from\" header with an accompanying `Referer` value. Here\nwe assume `Referer` has an `Arbitrary` instance to provide a random value. The endpoint generator\nfinishes with the name/weight indication.\n\nThe \"users\" endpoint requires two different request values. An Integer capture representing a user\nid as well as a `User` value. We hard-code the user id to `1001` using the monadic `pure` and assume that\n`User` has an `Arbitrary` instance to produce a random value. We finish with the endpoint's name/weight as necessary.\n\nThe \"post\" endpoint requires a `Text` query parameter. We provide a fixed set of possible values\nusing the `elements` function from the `QuickCheck` package. With a weight of 4, four instances of\nthe \"post\" endpoint will be produced, each with a random value from the specified set.\n\nFinally our API provides a `Raw` endpoint for serving static files, but we'd rather not benchmark\nit. Providing a 0 weight ensures that no request will be generated \n\n### Basic Auth\n\nA generator for an endpoint using a `BasicAuth` combinator requires both a function to convert the\nrequested user data type to `BasicAuthData` as well as a `Gen` value for the requested user data. \n\nexample:\n\n````haskell\ntype privateAPI = \"private\" :\u003e BasicAuth \"foo-realm\" User :\u003e PrivateAPI\n\ntoBasicAuthData :: User -\u003e BasicAuthData\ntoBasicAuthData user = ... \n\n-- assuming `User` has an `Arbitrary` instance\nlet generator = toBasicAuthData :\u003e: arbitrary :\u003e: (\"basicAuth\", 1)\n````\n\nThe information will be encoded as an `Authorization` header.\n\n## Supported tools\n\nThe following benchmarking tools are supported :\n\n- [wrk](https://github.com/wg/wrk)\n- [Drill](https://github.com/fcsonline/drill)\n- [Siege](src/Servant/Benchmark/Tools/Siege.hs)\n\nIf you'd like your favorite tool to be supported, don't hesitate to tell me so in an issue,\nor better yet submit a PR.\n\n## Next steps\n\n* Provide support for *servant-auth* combinators\n* Expand the support for benchmarking frameworks\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3kyro%2Fservant-benchmark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F3kyro%2Fservant-benchmark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3kyro%2Fservant-benchmark/lists"}