{"id":14067481,"url":"https://github.com/atheriel/httpproblems","last_synced_at":"2025-07-30T01:31:13.212Z","repository":{"id":56934825,"uuid":"337453802","full_name":"atheriel/httpproblems","owner":"atheriel","description":"Report errors from R APIs using \"Problem Details\" (RFC 7807)","archived":false,"fork":false,"pushed_at":"2021-07-06T17:17:58.000Z","size":34,"stargazers_count":6,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-05T16:41:18.347Z","etag":null,"topics":["plumber-api","r","rfc-7807","rfc7807"],"latest_commit_sha":null,"homepage":"","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/atheriel.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-02-09T15:44:15.000Z","updated_at":"2024-02-29T21:08:00.000Z","dependencies_parsed_at":"2022-08-21T06:50:43.245Z","dependency_job_id":null,"html_url":"https://github.com/atheriel/httpproblems","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/atheriel/httpproblems","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atheriel%2Fhttpproblems","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atheriel%2Fhttpproblems/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atheriel%2Fhttpproblems/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atheriel%2Fhttpproblems/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/atheriel","download_url":"https://codeload.github.com/atheriel/httpproblems/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/atheriel%2Fhttpproblems/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267792592,"owners_count":24144929,"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-07-29T02:00:12.549Z","response_time":2574,"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":["plumber-api","r","rfc-7807","rfc7807"],"created_at":"2024-08-13T07:05:37.150Z","updated_at":"2025-07-30T01:31:12.984Z","avatar_url":"https://github.com/atheriel.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, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\n```\n\n# httpproblems\n\n\u003c!-- badges: start --\u003e\n[![CRAN status](https://www.r-pkg.org/badges/version/httpproblems)](https://CRAN.R-project.org/package=httpproblems)\n[![R-CMD-check](https://github.com/atheriel/httpproblems/workflows/R-CMD-check/badge.svg)](https://github.com/atheriel/httpproblems/actions)\n\u003c!-- badges: end --\u003e\n\nThis R package is an answer to the question \"how can I report errors from my R\nAPI in a standard, consistent way?\"\n\nSpecifically, it implements the \"Problem Details\" specification from [RFC\n7807](https://tools.ietf.org/html/rfc7807), which is an emerging standard for\nerrors supported by many other languages and tools.\n\nAlthough **httpproblems** originated for use with\n[Plumber](https://www.rplumber.io) (see below), it has no dependencies of its\nown and can be used with any R web framework.\n\n## Installation\n\nYou can install the latest release of **httpproblems** from\n[CRAN](https://CRAN.R-project.org):\n\n``` r\ninstall.packages(\"httpproblems\")\n```\n\nor the development version from GitHub with\n\n```r\n# install.packages(\"remotes\")\nremotes::install_github(\"atheriel/httpproblems\")\n```\n\n## Usage\n\n**httpproblems** provides helpers to create a few common HTTP errors:\n\n* `bad_request()`\n* `not_found()`\n* `unauthorized()`\n* `forbidden()`\n* `conflict()`\n* `internal_server_error()`\n\nas well as a generic `http_problem()` that can be used with any valid status\ncode.\n\nThese functions return a normal list with elements [in line with the\nstandard](https://tools.ietf.org/html/rfc7807#section-3.1):\n\n```{r bad_request}\nlibrary(httpproblems)\n\nbody \u003c- bad_request(\"Parameter 'id' must be a number.\")\nstr(body)\n```\n\nThis object could be returned by an endpoint as normal after serialization to\ne.g. JSON.\n\nIn addition to these basic methods, **httpproblems** also has a set of\n`stop_for_http_problem()` functions:\n\n* `stop_for_bad_request()`\n* `stop_for_not_found()`\n* `stop_for_unauthorized()`\n* `stop_for_forbidden()`\n* `stop_for_conflict()`\n* `stop_for_internal_server_error()`\n\nThese leverage R's extensible condition system to issue custom errors for these\nproblems:\n\n```{r stop_for_bad_request, error=TRUE}\nstop_for_bad_request(\"Parameter 'id' must be a number.\")\n\n# What does the error actually contain?\ntryCatch(\n  stop_for_bad_request(\"Parameter 'id' must be a number.\"),\n  error = function(e) {\n    str(e)\n  }\n)\n```\n\nTypically, web frameworks allow you to control how uncaught errors are reported\n-- which can be combined with these helpers to ensure that all API errors have a\nconsistent format for your users.\n\n### Use with Plumber\n\nPlumber allows users to control how errors are handled (via `pr_set_error()`),\nwhich we can employ to produce a Problem Details structure for both expected\n*and* unexpected errors:\n\n```r\nlibrary(plumber)\n\npr() %\u003e%\n  pr_get(\"/bad\", function(req, res) {\n    stop_for_bad_request(\"The 'id' parameter must be a number.\")\n  }) %\u003e%\n  pr_get(\"/bug\", function(req, res) {\n    stop(\"Another R error.\")\n  }) %\u003e%\n  pr_set_error(function(req, res, err) {\n    # Force \"unboxed\" JSON and the Content-Type from RFC 7807.\n    res$serializer \u003c- serializer_unboxed_json(\n      type = \"application/problem+json\"\n    )\n    # If we have an http_problem_error, use its status and body\n    # fields. Otherwise, issue a 500 Internal Server Error.\n    if (inherits(err, \"http_problem_error\")) {\n      res$status \u003c- err$status\n      return(err$body)\n    }\n    if (isTRUE(req$pr$getDebug())) {\n      internal_server_error(detail = err$message)\n    } else {\n      internal_server_error()\n    }\n  }) %\u003e%\n  pr_run(port = 4444)\n```\n\nUsers interacting with this API will see the following:\n\n```shell\n$ curl -vs localhost:4444/bad\n\u003e GET /bad HTTP/1.1\n\u003e Host: localhost:4444\n\u003e User-Agent: curl/7.58.0\n\u003e Accept: */*\n\u003e \n\u003c HTTP/1.1 400 Bad Request\n\u003c Date: Tue, 09 Feb 2021 15:19:33 GMT\n\u003c Content-Type: application/problem+json\n\u003c Content-Length: 160\n\u003c \n{\n  \"type\": \"https://tools.ietf.org/html/rfc7231#section-6.5.1\",\n  \"title\": \"Bad Request\",\n  \"status\": 400,\n  \"detail\": \"The 'id' parameter must be a number.\"\n}\n$ curl -vs localhost:4444/bug\n\u003e GET /bug HTTP/1.1\n\u003e Host: localhost:4444\n\u003e User-Agent: curl/7.58.0\n\u003e Accept: */*\n\u003e \n\u003c HTTP/1.1 200 OK\n\u003c Date: Tue, 09 Feb 2021 15:19:59 GMT\n\u003c Content-Type: application/problem+json\n\u003c Content-Length: 150\n\u003c \n{\n  \"type\": \"https://tools.ietf.org/html/rfc7231#section-6.6.1\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Another R error.\"\n}\n```\n\nYou may also wish to use `not_found()` for Plumber's 404 handler via\n`pr_set_404()`.\n\n## License\n\nCopyright 2021 Aaron Jacobs\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n  https://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatheriel%2Fhttpproblems","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatheriel%2Fhttpproblems","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatheriel%2Fhttpproblems/lists"}