Real API responses often contain nested JSON arrays. A useful workflow is:
- read the response into R with
jsonlite; - infer an observed schema with
arrays = "rest"; - compact repeated alternatives into a maintainable shape;
- refine the few places where the API contract is stricter than the example.
Use simplifyVector = FALSE when the goal is to validate
the original JSON-like structure. If jsonlite simplifies arrays into
vectors or data frames, that simplified R object is still valid to
check, but it is no longer a direct view of the raw JSON response.
GitHub Search
For live data, read a GitHub REST API response without simplifying JSON arrays into data frames:
github_payload <- jsonlite::fromJSON(
"https://api.github.com/search/repositories?q=language:R+schema",
simplifyVector = FALSE,
simplifyDataFrame = FALSE,
simplifyMatrix = FALSE
)This vignette uses a curated subset of a real saved response so it
can run without network access. The source URL and capture details are
stored beside the JSON file in
inst/extdata/api/SOURCE.md.
github_payload <- jsonlite::fromJSON(
payload_path("github-search-repositories.json"),
simplifyVector = FALSE,
simplifyDataFrame = FALSE,
simplifyMatrix = FALSE
)
jsonlite::toJSON(github_payload, pretty = TRUE, auto_unbox = TRUE)
#> {
#> "total_count": 167,
#> "incomplete_results": false,
#> "items": [
#> {
#> "id": 48069228,
#> "node_id": "MDEwOlJlcG9zaXRvcnk0ODA2OTIyOA==",
#> "name": "sevenbridges-r",
#> "full_name": "sbg/sevenbridges-r",
#> "private": false,
#> "html_url": "https://github.com/sbg/sevenbridges-r",
#> "description": "Seven Bridges API Client, CWL Schema, Meta Schema, and SDK Helper in R",
#> "fork": false,
#> "created_at": "2015-12-15T21:10:57Z",
#> "updated_at": "2026-04-13T07:53:29Z",
#> "pushed_at": "2022-01-28T14:06:08Z",
#> "size": 3572,
#> "stargazers_count": 37,
#> "watchers_count": 37,
#> "language": "R",
#> "has_issues": true,
#> "has_projects": true,
#> "has_downloads": true,
#> "has_wiki": true,
#> "has_pages": true,
#> "has_discussions": false,
#> "forks_count": 14,
#> "archived": false,
#> "disabled": false,
#> "open_issues_count": 13,
#> "allow_forking": true,
#> "is_template": false,
#> "topics": [
#> "api-client",
#> "bioconductor",
#> "bioinformatics",
#> "cloud",
#> "common-workflow-language",
#> "sevenbridges"
#> ],
#> "visibility": "public",
#> "default_branch": "master",
#> "score": 1,
#> "owner": {
#> "login": "sbg",
#> "id": 233118,
#> "node_id": "MDEyOk9yZ2FuaXphdGlvbjIzMzExOA==",
#> "html_url": "https://github.com/sbg",
#> "type": "Organization",
#> "site_admin": false
#> },
#> "license": {
#> "key": "apache-2.0",
#> "name": "Apache License 2.0",
#> "spdx_id": "Apache-2.0",
#> "url": "https://api.github.com/licenses/apache-2.0",
#> "node_id": "MDc6TGljZW5zZTI="
#> }
#> },
#> {
#> "id": 134324345,
#> "node_id": "MDEwOlJlcG9zaXRvcnkxMzQzMjQzNDU=",
#> "name": "dataspice",
#> "full_name": "ropensci/dataspice",
#> "private": false,
#> "html_url": "https://github.com/ropensci/dataspice",
#> "description": ":hot_pepper: Create lightweight schema.org descriptions of your datasets",
#> "fork": false,
#> "created_at": "2018-05-21T20:55:32Z",
#> "updated_at": "2025-12-21T21:16:10Z",
#> "pushed_at": "2025-09-24T14:25:06Z",
#> "size": 3188,
#> "stargazers_count": 164,
#> "watchers_count": 164,
#> "language": "R",
#> "has_issues": true,
#> "has_projects": true,
#> "has_downloads": true,
#> "has_wiki": true,
#> "has_pages": false,
#> "has_discussions": false,
#> "forks_count": 26,
#> "archived": false,
#> "disabled": false,
#> "open_issues_count": 34,
#> "allow_forking": true,
#> "is_template": false,
#> "topics": [
#> "data",
#> "dataset",
#> "metadata",
#> "r",
#> "r-package",
#> "rstats",
#> "schema-org",
#> "unconf",
#> "unconf18"
#> ],
#> "visibility": "public",
#> "default_branch": "main",
#> "score": 1,
#> "owner": {
#> "login": "ropensci",
#> "id": 1200269,
#> "node_id": "MDEyOk9yZ2FuaXphdGlvbjEyMDAyNjk=",
#> "html_url": "https://github.com/ropensci",
#> "type": "Organization",
#> "site_admin": false
#> },
#> "license": {
#> "key": "other",
#> "name": "Other",
#> "spdx_id": "NOASSERTION",
#> "url": {},
#> "node_id": "MDc6TGljZW5zZTA="
#> }
#> }
#> ]
#> }
github_schema <- github_payload |>
schema_infer(keys = "required", arrays = "rest") |>
schema_compact()
github_schema
#> {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named",
#> "must.include": ["total_count", "incomplete_results", "items"]
#> },
#> "fields": {
#> "total_count": {
#> "check": {
#> "kind": "int"
#> }
#> },
#> "incomplete_results": {
#> "check": {
#> "kind": "flag"
#> }
#> },
#> "items": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named",
#> "must.include": ["id", "node_id", "name", "full_name", "private", "html_url", "description", "fork", "created_at", "updated_at", "pushed_at", "size", "stargazers_count", "watchers_count", "language", "has_issues", "has_projects", "has_downloads", "has_wiki", "has_pages", "has_discussions", "forks_count", "archived", "disabled", "open_issues_count", "allow_forking", "is_template", "topics", "visibility", "default_branch", "score", "owner", "license"]
#> },
#> "fields": {
#> "topics": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "string"
#> }
#> }
#> },
#> "owner": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named",
#> "must.include": ["login", "id", "node_id", "html_url", "type", "site_admin"]
#> },
#> "fields": {
#> "id": {
#> "check": {
#> "kind": "int"
#> }
#> },
#> "site_admin": {
#> "check": {
#> "kind": "flag"
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["login", "node_id", "html_url", "type"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> },
#> "license": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named",
#> "must.include": ["key", "name", "spdx_id", "url", "node_id"]
#> },
#> "fields": {
#> "url": {
#> "any": [
#> {
#> "check": {
#> "kind": "string"
#> }
#> },
#> {
#> "check": {
#> "kind": "null"
#> }
#> }
#> ]
#> }
#> },
#> "groups": [
#> {
#> "names": ["key", "name", "spdx_id", "node_id"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }
#> },
#> "groups": [
#> {
#> "names": ["id", "size", "stargazers_count", "watchers_count", "forks_count", "open_issues_count", "score"],
#> "check": {
#> "kind": "int"
#> }
#> },
#> {
#> "names": ["node_id", "name", "full_name", "html_url", "description", "created_at", "updated_at", "pushed_at", "language", "visibility", "default_branch"],
#> "check": {
#> "kind": "string"
#> }
#> },
#> {
#> "names": ["private", "fork", "has_issues", "has_projects", "has_downloads", "has_wiki", "has_pages", "has_discussions", "archived", "disabled", "allow_forking", "is_template"],
#> "check": {
#> "kind": "flag"
#> }
#> }
#> ]
#> }
#> }
#> }
#> }The items field is inferred as an unnamed list whose
rest schema describes repository-like objects.
bad_github <- github_payload
bad_github$items[[1L]]$owner$id <- "not an integer"
github_schema |>
schema_validate(github_payload, mode = "test")
#> [1] TRUE
github_schema |>
schema_validate(bad_github, mode = "check", name = "github")
#> [1] "github$items[[1]]$owner$id: Must be of type 'single integerish value', not 'character'"CrossRef Works
For live CrossRef data:
crossref_payload <- jsonlite::fromJSON(
"https://api.crossref.org/works?query.title=schema&rows=2",
simplifyVector = FALSE,
simplifyDataFrame = FALSE,
simplifyMatrix = FALSE
)Again, the runnable example uses a curated subset of a real saved response.
crossref_payload <- jsonlite::fromJSON(
payload_path("crossref-works.json"),
simplifyVector = FALSE,
simplifyDataFrame = FALSE,
simplifyMatrix = FALSE
)
jsonlite::toJSON(crossref_payload, pretty = TRUE, auto_unbox = TRUE)
#> {
#> "status": "ok",
#> "message-type": "work-list",
#> "message-version": "1.0.0",
#> "message": {
#> "total-results": 13146,
#> "items-per-page": 2,
#> "query": {
#> "start-index": 0,
#> "search-terms": {}
#> },
#> "items": [
#> {
#> "DOI": "10.33115/udg_bib/msr.v17i0.22300",
#> "type": "journal-article",
#> "publisher": "Edicions A Peticio",
#> "title": "Schema saffico e schema zaglialesco",
#> "container-title": "Mot so razo",
#> "short-container-title": "MSR",
#> "volume": "17",
#> "ISSN": [
#> "2385-4359",
#> "1575-5568"
#> ],
#> "score": 15.4821,
#> "URL": "https://doi.org/10.33115/udg_bib/msr.v17i0.22300",
#> "reference-count": 0,
#> "is-referenced-by-count": 0,
#> "references-count": 0,
#> "issued": {
#> "date-parts": [
#> [
#> 2019,
#> 9,
#> 5
#> ]
#> ]
#> },
#> "created": {
#> "date-parts": [
#> [
#> 2019,
#> 9,
#> 6
#> ]
#> ],
#> "date-time": "2019-09-06T03:43:13Z",
#> "timestamp": 1567741393000
#> },
#> "published": {
#> "date-parts": [
#> [
#> 2019,
#> 9,
#> 5
#> ]
#> ]
#> },
#> "published-online": {
#> "date-parts": [
#> [
#> 2019,
#> 9,
#> 5
#> ]
#> ]
#> },
#> "deposited": {
#> "date-parts": [
#> [
#> 2019,
#> 9,
#> 6
#> ]
#> ],
#> "date-time": "2019-09-06T03:43:15Z",
#> "timestamp": 1567741395000
#> },
#> "author": [
#> {
#> "given": "Lorenzo",
#> "family": "Mainini",
#> "sequence": "first",
#> "affiliation": []
#> }
#> ],
#> "link": [
#> {
#> "URL": "https://revistes.udg.edu/mot-so-razo/article/viewFile/22300/26052",
#> "content-type": "application/pdf",
#> "content-version": "vor",
#> "intended-application": "text-mining"
#> },
#> {
#> "URL": "https://revistes.udg.edu/mot-so-razo/article/viewFile/22300/26052",
#> "content-type": "unspecified",
#> "content-version": "vor",
#> "intended-application": "similarity-checking"
#> }
#> ]
#> },
#> {
#> "DOI": "10.5040/9780567678393.177",
#> "type": "other",
#> "publisher": "Bloomsbury Publishing Plc",
#> "title": "Schema",
#> "container-title": "The Dictionary of the Bible and Ancient Media",
#> "ISBN": [
#> "9780567678393",
#> "9780567222497"
#> ],
#> "score": 15.337,
#> "URL": "https://doi.org/10.5040/9780567678393.177",
#> "reference-count": 0,
#> "is-referenced-by-count": 0,
#> "references-count": 0,
#> "issued": {
#> "date-parts": [
#> 2017
#> ]
#> },
#> "created": {
#> "date-parts": [
#> [
#> 2020,
#> 2,
#> 28
#> ]
#> ],
#> "date-time": "2020-02-28T14:26:46Z",
#> "timestamp": 1582900006000
#> },
#> "published": {
#> "date-parts": [
#> 2017
#> ]
#> },
#> "published-print": {
#> "date-parts": [
#> 2017
#> ]
#> },
#> "deposited": {
#> "date-parts": [
#> [
#> 2020,
#> 9,
#> 2
#> ]
#> ],
#> "date-time": "2020-09-02T18:28:58Z",
#> "timestamp": 1599071338000
#> }
#> }
#> ]
#> }
#> }
crossref_schema <- crossref_payload |>
schema_infer(keys = "named", arrays = "rest") |>
schema_compact()
crossref_schema
#> {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "message": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "query": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "start-index": {
#> "check": {
#> "kind": "int"
#> }
#> },
#> "search-terms": {
#> "check": {
#> "kind": "null"
#> }
#> }
#> }
#> },
#> "items": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "score": {
#> "check": {
#> "kind": "number"
#> }
#> },
#> "published-online": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "int"
#> }
#> }
#> }
#> }
#> }
#> },
#> "author": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "affiliation": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["given", "family", "sequence"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }
#> },
#> "link": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "groups": [
#> {
#> "names": ["URL", "content-type", "content-version", "intended-application"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }
#> },
#> "published-print": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "int"
#> }
#> }
#> }
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["DOI", "type", "publisher", "title", "container-title", "short-container-title", "volume", "URL"],
#> "check": {
#> "kind": "string"
#> }
#> },
#> {
#> "names": ["ISSN", "ISBN"],
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "string"
#> }
#> }
#> },
#> {
#> "names": ["reference-count", "is-referenced-by-count", "references-count"],
#> "check": {
#> "kind": "int"
#> }
#> },
#> {
#> "names": ["issued", "published"],
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "any": [
#> {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "int"
#> }
#> }
#> },
#> {
#> "check": {
#> "kind": "int"
#> }
#> }
#> ]
#> }
#> }
#> }
#> },
#> {
#> "names": ["created", "deposited"],
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "int"
#> }
#> }
#> }
#> },
#> "date-time": {
#> "check": {
#> "kind": "string"
#> }
#> },
#> "timestamp": {
#> "check": {
#> "kind": "number"
#> }
#> }
#> }
#> }
#> ]
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["total-results", "items-per-page"],
#> "check": {
#> "kind": "int"
#> }
#> }
#> ]
#> }
#> },
#> "groups": [
#> {
#> "names": ["status", "message-type", "message-version"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }CrossRef date-parts entries may be a scalar year or a
tuple-like year/month/day array in this saved response.
Inference records the observed array shapes, then a small manual edit
can define the reusable date component once and reference it from every
matching date-parts position.
The path below walks through the inferred homogeneous arrays. The
first rest means “the schema for each item”; the final
rest means “the schema for each date-parts entry”.
$message$items$rest$`published-online`$`date-parts`$rest
date_part <- schema_any(
schema_check("int", lower = 0),
list(
check = list(kind = "list", min.len = 1L, max.len = 3L),
keys = list(type = "unnamed"),
positions = list(
schema_check("int", lower = 0),
schema_check("int", lower = 1, upper = 12),
schema_check("int", lower = 1, upper = 31)
)
)
)
crossref_schema <- crossref_schema |>
schema_add_def("crossref_date_part", date_part)
schema_find(crossref_schema, schema_where_path("(^|\\$)`date-parts`\\$rest$"))
#> [1] "$message$items$rest$issued$`date-parts`$rest"
#> [2] "$message$items$rest$published$`date-parts`$rest"
#> [3] "$message$items$rest$`published-online`$`date-parts`$rest"
#> [4] "$message$items$rest$created$`date-parts`$rest"
#> [5] "$message$items$rest$deposited$`date-parts`$rest"
#> [6] "$message$items$rest$`published-print`$`date-parts`$rest"
crossref_schema <- crossref_schema |>
schema_replace_where(
schema_where_path("(^|\\$)`date-parts`\\$rest$"),
schema_ref("crossref_date_part")
)
crossref_schema
#> {
#> "$defs": {
#> "crossref_date_part": {
#> "any": [
#> {
#> "check": {
#> "kind": "int",
#> "lower": 0
#> }
#> },
#> {
#> "check": {
#> "kind": "list",
#> "min.len": 1,
#> "max.len": 3
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "positions": [
#> {
#> "check": {
#> "kind": "int",
#> "lower": 0
#> }
#> },
#> {
#> "check": {
#> "kind": "int",
#> "lower": 1,
#> "upper": 12
#> }
#> },
#> {
#> "check": {
#> "kind": "int",
#> "lower": 1,
#> "upper": 31
#> }
#> }
#> ]
#> }
#> ]
#> }
#> },
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "message": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "query": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "start-index": {
#> "check": {
#> "kind": "int"
#> }
#> },
#> "search-terms": {
#> "check": {
#> "kind": "null"
#> }
#> }
#> }
#> },
#> "items": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "score": {
#> "check": {
#> "kind": "number"
#> }
#> },
#> "published-online": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "$ref": "#/$defs/crossref_date_part"
#> }
#> }
#> }
#> },
#> "author": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "affiliation": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["given", "family", "sequence"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }
#> },
#> "link": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "groups": [
#> {
#> "names": ["URL", "content-type", "content-version", "intended-application"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }
#> },
#> "published-print": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "$ref": "#/$defs/crossref_date_part"
#> }
#> }
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["DOI", "type", "publisher", "title", "container-title", "short-container-title", "volume", "URL"],
#> "check": {
#> "kind": "string"
#> }
#> },
#> {
#> "names": ["ISSN", "ISBN"],
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "check": {
#> "kind": "string"
#> }
#> }
#> },
#> {
#> "names": ["reference-count", "is-referenced-by-count", "references-count"],
#> "check": {
#> "kind": "int"
#> }
#> },
#> {
#> "names": ["issued", "published"],
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "$ref": "#/$defs/crossref_date_part"
#> }
#> }
#> }
#> },
#> {
#> "names": ["created", "deposited"],
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "named"
#> },
#> "fields": {
#> "date-parts": {
#> "check": {
#> "kind": "list"
#> },
#> "keys": {
#> "type": "unnamed"
#> },
#> "rest": {
#> "$ref": "#/$defs/crossref_date_part"
#> }
#> },
#> "date-time": {
#> "check": {
#> "kind": "string"
#> }
#> },
#> "timestamp": {
#> "check": {
#> "kind": "number"
#> }
#> }
#> }
#> }
#> ]
#> }
#> }
#> },
#> "groups": [
#> {
#> "names": ["total-results", "items-per-page"],
#> "check": {
#> "kind": "int"
#> }
#> }
#> ]
#> }
#> },
#> "groups": [
#> {
#> "names": ["status", "message-type", "message-version"],
#> "check": {
#> "kind": "string"
#> }
#> }
#> ]
#> }
bad_crossref <- crossref_payload
bad_crossref$message$items[[1L]]$`published-online`$`date-parts`[[1L]][[2L]] <- 13L
crossref_schema |>
schema_validate(crossref_payload, mode = "test")
#> [1] TRUE
crossref_schema |>
schema_validate(bad_crossref, mode = "check", name = "crossref")
#> [1] "crossref$message$items[[1]]$published-online$date-parts[[1]] failed all branches of `any`: [1] crossref$message$items[[1]]$published-online$date-parts[[1]]: Must be of type 'single integerish value', not 'list' | [2] crossref$message$items[[1]]$published-online$date-parts[[1]][[2]]: Element 1 is not <= 12"When a reusable component has a clear domain name, author it
explicitly with $defs and $ref, then use
schema_replace_where() to replace repeated logical paths
with a shared reference. schema_compact() deliberately
avoids inventing reusable definition names for you.