Changelog
legihelpR (development version)
-
API failures now stop with classed errors that separate temporary problems from ones that will fail again. All inherit from
legihelpR_error:legihelpR_rate_limited,legihelpR_unavailable,legihelpR_network_error,legihelpR_quota_exceeded,legihelpR_invalid_key,legihelpR_access_denied,legihelpR_invalid_request,legihelpR_invalid_response, pluslegihelpR_api_errorandlegihelpR_http_erroron errors from API bodies and HTTP statuses. Conditions carryop,http_status,api_message, andretry_afterfields and an actionable hint. See?"legihelpR-errors".- Retries still depend on the HTTP status (429 and 503), never on message wording, so a rate-limit response is never mistaken for an exhausted allowance and stopped early. Read-only functions now also retry HTTP 502 and 504 and network failures, and an HTTP 200 API error that plainly reports rate limiting is retried. Other API errors, such as an invalid key or id, still stop on the first attempt.
- A
Retry-Afterlonger thanlegihelpR.max_retry_wait(default 60 seconds) stops with the requested wait inretry_after, instead of blocking the session. -
setMonitor()keeps retrying only HTTP 429, HTTP 503, and rate-limit messages, where LegiScan did not handle the request. After a network failure or gateway error its error says the change may already have been applied. - API and dataset access keys are removed from error messages. LegiScan echoes the request URL, including the key, in some alerts. Errors no longer carry the httr2 request, whose URL contains the keys.
-
getDatasetRaw()errors instead of saving a file when the download is not a ZIP archive, and responses that are not JSON raiselegihelpR_invalid_response.
Breaking: HTTP errors no longer have httr2’s
httr2_http_<status>classes or itsrespandrequestfields. Catch the legihelpR classes and usehttp_statusinstead.-
Inputs are now validated locally so predictable mistakes no longer spend API quota:
- Search queries longer than the API’s 1024-byte (UTF-8) limit error with the actual size; queries are never truncated or split. Accented and other non-ASCII characters count as 2-4 bytes. (The legiscan.com search box has a stricter 512-character limit that does not apply to the API.)
- Identifiers (
billID,peopleID,sessionID,billIDs, …) must be positive whole numbers or strings of digits. -
statemust be a US state abbreviation,DC, orUS(plusALLfor searches) and is uppercased before sending. Searchyear, monitor listrecord, and datasetaccessKeyare checked against documented values. State and year are not checked whensessionIDreplaces them. - Download functions check that
fileis not a directory and that its folder exists before requesting data.
Breaking:
getDatasetList()now errors, instead of warning, whenyearis not a 4 digit year.API requests are now spaced at least 0.6 seconds apart to stay under LegiScan’s ~2 requests/second sliding-window limit (effective October 1, 2026). This replaces the previous throttle, which allowed an initial burst of 30 requests. Pacing covers every endpoint, search pages, and retry attempts, and is shared within one R process. Set
options(legihelpR.request_interval = <seconds>)to adjust it.Compatibility: empty
getMasterListRaw()andgetMonitorListRaw()results now have typed columns matching their documented API fields, rather than zero columns. Usenrow(x) == 0to detect no bills;length(x) == 0,ncol(x) == 0, and column-presence checks no longer detect emptiness. Nonempty responses and API error handling are unchanged.Vignette API examples are explicitly unevaluated so extracted code does not make live requests during package checks.
setlegiKey(install = TRUE)now separates the new assignment from an existing final line without a newline, preserving existing settings and ensuring the key is not swallowed by a comment.Search functions now collect pages before combining results, avoiding repeated copies of previously fetched rows while preserving result order and columns.
Search functions now validate
query,page, andmaxPagesbefore making quota-consuming requests, and session-scoped searches omit incompatible state and year filters.getDataset()now supports LegiScan’sformatparameter; both dataset download functions acceptjsonorcsvcase-insensitively and reject invalid formats before making a request.API response and key validation now handle malformed values cleanly without including a supplied key in error logs.
setlegiKey()matches only actuallegiKey=entries in.Renviron, checks setup and backup failures, and safely quotes the stored value.Document and sponsored-session messages now use fields present in LegiScan’s documented response schema.
getDatasetRaw()now takesformatafterlegiKey, matching the argument order ofgetDataset(). Positional calls that passedformatthird must be updated to name the argument.Internal request building no longer uses R’s native pipe. This is a style change only:
httr2anddplyrboth require R >= 4.1, so the package’s effective minimum R version is unchanged.Expanded offline regression coverage and declared the testthat version used by the test helpers.
legihelpR 0.3.2
-
legiSearch()andlegiSearchRaw()now return a zero-row data frame with the documented columns, instead ofNULL, when a search matches nothing. The “No results found” warning is unchanged. Downstream code can callnrow(), select columns, or bind results without special-casing empty searches; existingis.null()guards will no longer trigger. -
maxPagesinlegiSearch()andlegiSearchRaw()now caps the number of pages fetched, as documented, rather than acting as a maximum page number. Behavior only changes when paginating from a custom startingpage> 1. -
legiSearchRaw()no longer errors (“argument is of length zero”) when a response arrives without asummary$page_total; it stops paginating and returns what it collected. -
legiSearch()drops thesummaryblock from responses by name rather than by position, matchinggetMasterList(), so a reordered response can never silently discard a result row. -
legiSearch()usessummary$page_totalto detect the final page instead of the “fewer than 50 rows” heuristic, which spent one extra API query whenever the result count was an exact multiple of the page size. -
getMasterList()no longer emits a blank message when a response has nosessionblock. -
DESCRIPTIONnow declares the requiredhttr2 (>= 1.1.0)and drops the unusedLazyDatafield.
legihelpR 0.3.1
- Renamed function arguments to a consistent camelCase ID convention (e.g.
billID,sessionID,peopleID,legiKey). - Document functions (
getText(),getAmendment(),getSupplement(),getDataset()) gained afileargument to decode base64 documents to disk. - Search pagination is capped with
maxPages(default 10) to protect API quota; useInfto fetch every page. - Added a change-detection vignette.