{"id":13401322,"url":"https://github.com/thomasp85/reqres","last_synced_at":"2025-04-09T06:13:32.629Z","repository":{"id":51174722,"uuid":"98390664","full_name":"thomasp85/reqres","owner":"thomasp85","description":"Powerful classes for http requests and responses","archived":false,"fork":false,"pushed_at":"2025-03-31T07:04:24.000Z","size":4359,"stargazers_count":38,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-31T15:27:05.265Z","etag":null,"topics":["http","http-server","request","response","rstats"],"latest_commit_sha":null,"homepage":"https://reqres.data-imaginist.com","language":"R","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/thomasp85.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-26T07:01:35.000Z","updated_at":"2025-03-31T07:00:56.000Z","dependencies_parsed_at":"2022-09-10T03:32:59.278Z","dependency_job_id":null,"html_url":"https://github.com/thomasp85/reqres","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasp85%2Freqres","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasp85%2Freqres/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasp85%2Freqres/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasp85%2Freqres/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thomasp85","download_url":"https://codeload.github.com/thomasp85/reqres/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247987285,"owners_count":21028895,"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":["http","http-server","request","response","rstats"],"created_at":"2024-07-30T19:01:01.434Z","updated_at":"2025-04-09T06:13:32.613Z","avatar_url":"https://github.com/thomasp85.png","language":"R","funding_links":[],"categories":["R"],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, echo = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"README-\"\n)\n```\n\n# reqres \u003cimg src=\"man/figures/logo.png\" align=\"right\"/\u003e\n\n\u003c!-- badges: start --\u003e\n[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)\n[![R-CMD-check](https://github.com/thomasp85/reqres/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/thomasp85/reqres/actions/workflows/R-CMD-check.yaml)\n[![CRAN status](https://www.r-pkg.org/badges/version/reqres)](https://CRAN.R-project.org/package=reqres)\n[![Codecov test coverage](https://codecov.io/gh/thomasp85/reqres/graph/badge.svg)](https://app.codecov.io/gh/thomasp85/reqres)\n\u003c!-- badges: end --\u003e\n\nWhile the http protocol is rather basic in essence, it can be a pain to work\nwith. `reqres` is here to soothe the pain somewhat by providing two powerful\nclasses for handling all parts of request and response handling during a http\nexchange. *This is not a web server*, instead it focuses on making life easier\nfor developers of web servers by extracting the complexity of cookies, headers,\ncontent negotiation, and the likes into neat little classes. `reqres` builds\nupon the [`rook`](https://github.com/jeffreyhorner/Rook/blob/a5e45f751/README.md)\nspecifications and is thus well suited for\n[`httpuv`-based](https://github.com/rstudio/httpuv) webservers.\n\n## Features\n`reqres` draws a lot of inspiration from [express.js](https://expressjs.com) and\nthe `Request` and `Response` classes is aiming for feature parity with those\nfrom express. The `Request` class provides automatic parsing of the query string\nalong with parsing of the body based on the `Content-Type` header (with\ndecompression if `Content-Encoding` is provided). Further, it provides content\nnegotiation based on the `Accept(-*)` headers. The `Response` class allows you\nto set headers and cookies easily, assign arbitrary data for later use, and\nautomatically format the body based on content negotiation with the `Request`\nobject that it is responding to (again, it will compress automatically if the\n`Accept-Encoding` header allows it). If any part of the content negotiation\nfails the correct response status code will be set, making the response ready to\nsend.\n\n`reqres` comes with a range of parsers and formatters making it work out of the\nbox with json, xml, html, csv, tab, multipart, and www-form-urlencoded payloads.\nIt is easy to either modify these or provide your own parsers and formatters if\nneeded - `reqres` will take care of the content negotiation and simply call your\ncustom parser/formatter if chosen.\n\n## Installation\nreqrescan be installed from CRAN with `install.packages('reqres')` or the\ndevelopment version can be installed from github:\n\n```{r, eval=FALSE}\n# install.packages('devtools')\ndevtools::install_github('thomasp85/reqres')\n```\n\n## Demo\nBelow is a quick demo of some of the features in `reqres`. It uses the\n`fake_request()` in `fiery` to mock a rook request so it can be used without\nsetting up a webserver:\n\n```{r}\nlibrary(reqres)\n\n# We start by mocking our request\nrook \u003c- fiery::fake_request(\n    url = 'http://www.example.com/summary?id=2347\u0026user=Thomas+Lin+Pedersen',\n    content = '{\"name\":[\"Thomas Lin Pedersen\"],\"age\":[31],\"homepage\":[\"www.data-imaginist.com\",\"www.github.com/thomasp85\"]}',\n    headers = list(\n        Content_Type = 'application/json',\n        Accept = 'application/json, application/xml; q=0.5, text/*; q=0.3',\n        Accept_Encoding = 'gzip, br'\n    )\n)\n\n# A Request object can now be created\nreq \u003c- Request$new(rook)\nreq\n\n# ... along with a response\nres \u003c- req$respond()\nres\n```\n\n### Request\nA lot of information is already available, such as the query and other parts of\nthe url, but the body is not filled in automatically.\n\n```{r}\nreq$host\nreq$query\nreq$body\n```\n\nThe body can easily be parsed though, as long as a parser exists for the\nprovided content type.\n\n```{r}\nreq$is('json')\nreq$parse(json = parse_json())\nreq$body\n```\n\nInstead of inspecting it manually you can simply provide a range of parsers and\nlet the object choose the correct one itself\n\n```{r}\nreq$set_body(NULL)\nreq$parse(\n    txt = parse_plain(),\n    html = parse_html(),\n    json = parse_json()\n)\nreq$body\n```\n\nIn the case that none of the provided parsers fits the content type, the\nresponse will automatically get updated with the correct error code\n\n```{r}\nreq$set_body(NULL)\nreq$parse(txt = parse_plain())\nres\n```\n\nTo facilitate all this `reqres` comes with a mapping of standard mime types to\nthe provided parsers. This can simply be supplied to the parse method\n\n```{r}\nreq$set_body(NULL)\nreq$parse(default_parsers)\nreq$body\n```\n\n### Response\nWhile the request is mainly intended to be read from, the response should be\nwritten to. The `Response` class contains a slew of methods to easily set\nheaders, cookies, etc.\n\n```{r}\nres$set_header('Date', to_http_date(Sys.time()))\nres$get_header('Date')\nres$set_cookie('user', req$query$id, max_age = 9000L)\nres$has_cookie('user')\n```\n\nFurthermore, it contains its own data store where arbitrary information can be\nstored so as to pass it between middleware etc. This data will never be part of\nthe actual response.\n\n```{r}\nres$set_data('alphabet', letters)\nres$get_data('alphabet')\n```\n\nFiles can be attached and marked for download, setting the relevant headers\nautomatically\n\n```{r}\nres$attach(system.file('NEWS.md', package = 'reqres'))\nres$get_header('Content-Type')\nres$get_header('Content-Disposition')\n```\n\nOften we need to provide a payload in the form of a body. This can be any type\nof R object until the response is handed off to the server, where it should be\neither a string or a raw vector.\n\n```{r}\nres$remove_header('Content-Disposition')\nres$body \u003c- head(mtcars)\nres$body\n```\n\nBased on the `Accept` header in the request it can be formatted correctly thus\nmaking it ready to send back to the client. As this request contains an\n`Accept-Encoding` header it will be compressed as well.\n\n```{r}\nres$format(json = format_json())\nres$body\nres$get_header('Content-Type')\nres$get_header('Content-Encoding')\n```\n\nThe content negotiation understands wildcards as well\n\n```{r}\nres$body \u003c- head(mtcars)\nreq$get_header('Accept')\nres$format(csv = format_table(sep = ','), compress = FALSE)\nres$body\nres$get_header('Content-Type')\n```\n\nA default formatter mapping exists in parallel to `default_parsers` for the\n`Request$format()` method.\n\n```{r}\nres$body \u003c- head(mtcars)\nres$format(default_formatters, compress = FALSE)\nres$body\n```\n\nIt is easy to define your own formatters and add them along the defaults\n\n```{r}\nres$body \u003c- head(mtcars)\nres$format('text/yaml' = yaml::as.yaml, compress = FALSE)\nres$body\n```\n\n## Code of Conduct\nPlease note that the 'reqres' project is released with a\n[Contributor Code of Conduct](https://reqres.data-imaginist.com/CODE_OF_CONDUCT.html).\nBy contributing to this project, you agree to abide by its terms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasp85%2Freqres","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomasp85%2Freqres","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasp85%2Freqres/lists"}