{"id":14986452,"url":"https://github.com/oai/oascomply","last_synced_at":"2025-10-19T11:32:03.997Z","repository":{"id":163148987,"uuid":"629114068","full_name":"OAI/oascomply","owner":"OAI","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-19T20:19:56.000Z","size":1842,"stargazers_count":24,"open_issues_count":19,"forks_count":7,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-01-29T16:21:38.210Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OAI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-04-17T16:41:52.000Z","updated_at":"2024-12-16T11:47:14.000Z","dependencies_parsed_at":"2023-10-11T07:08:59.384Z","dependency_job_id":"cfcc7501-6841-4c09-86e0-8c4ddfdf36e0","html_url":"https://github.com/OAI/oascomply","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OAI%2Foascomply","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OAI%2Foascomply/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OAI%2Foascomply/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OAI%2Foascomply/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OAI","download_url":"https://codeload.github.com/OAI/oascomply/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237117281,"owners_count":19258383,"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":[],"created_at":"2024-09-24T14:12:53.763Z","updated_at":"2025-10-19T11:32:03.055Z","avatar_url":"https://github.com/OAI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenAPI Compliance\n\nThis repository contains the OpenAPI Compliance Project, the first\npiece of which is the OpenAPI Specification Compliance Parser.\n\nThe `oascomply` command-line tool takes an API description, as a single document or as several documents linked by JSON References (`$ref`) and indicates whether or not it is syntactically and semantically valid.  It can optionally serialize an RDF graph of the parsed API description to `stdout` in any format supported by `rdflib`, as well as a custom format intended to be more human-readable.\n\nThe `oas30-schema` command-line tool is an OAS 3.0-specific JSON Schema implementation, based on the `jschon` implementation.\n\n## Status\n\nThe OAS Compliance Parser is expected to reach 1.0 status by\nlate 2023.  The current status of the project is\n[pre-Milestone 1](https://tinyurl.com/4kth84k8).\n\n* Milestone 1: (June 1, 2023) Basic parsing and syntax validation; RDF graph construction\n* Milestone 2: (mid-July, 2023) User-friendly error reporting, reasonably complete and extensible syntax validation\n* Milestone 3: (late August, 2023) Basic semantic validation using the RDF graph\n* Milestone 4: (October 2023) Reasonably complete and extensible semantic validation, fully documented 1.0 release publishable on PyPI\n\nCurrently, only OAS 3.0 is supported, although OAS 3.1 support is planned.\n\n## Requirements and Installation\n\n`oascomply` is a Python package with several command-line interfaces:\n\n* `oascomply` parses and validates OAS 3.x API descriptions\n* `oas30-schema` validates instances against JSON Schemas that use the OpenAPI 3.0 schema dialect, including `\"format\" validation\n* `yaml-to-json` does what it says, as converting a YAML API description\n  to JSON will result in\n  [substantial performance improvements](https://github.com/handrews/oasparser/issues/9) if running `oascomply` on the same document repeatedly\n* `patch-oas-schemas` is used by package maintainers to update the modified\n  OAS 3.x JSON Schemas used by `oascomply`\n\n`oascomply` requires Python 3.8 or later, and must be checked out from GitHub\nand installed using [`poetry`](https://python-poetry.org/docs/).  See the\n[Installation Guide](INSTALL.md) for more detailed instructions.\n\n## Parsing API descriptions\n\nAPI descriptions consist of one or more documents.\n\nA single, self-contained document can be validated like this:\n\n```\n~/src/oascomply % oascomply -f tutorial/minimal.json\nYour API description is valid!\n```\n\n### Multi-document API descriptions\n\nFor a multi-document API description where the files have file extensions\n(`schemas/foo.json`) but the references do not (`\"$ref\": \"schemas/foo\"`),\nwe need to make a distinction between two concepts for each document:\n\n* its _**URL**_ (for local files, the `file:` URL from which it was read)\n* its _**URI**_ (the identifier used to resolve references and in the parsed graph discussed further down)\n\nBy default, `oascomply` assumes that the URI is the same as the URL.\nIf we try that default behavior with our referencing example, it won't work:\n\n```\n~/src/oascomply % oascomply -f tutorial/references/openapi.json -f tutorial/references/pathitems/foo.json -f tutorial/references/schemas/bar.json\nERROR:oascomply.oas30dialect:FOUND: file:///Users/handrews/src/oascomply/tutorial/references/schemas/bar\nERROR:oascomply.apidescription:Reference without suffix attempted despite target resource being registered under a URI with suffix\n\nThe above error can be fixed either by using -x:\n\n\t-x -f tutorial/references/schemas/bar.json\n\n... or by using the two-argument form of -f:\n\n\t-f tutorial/references/schemas/bar.json file:///Users/handrews/src/oascomply/tutorial/references/schemas/bar\n```\n\nLet's try the `-x` option, which creates URIs by just stripping the suffix off, since that's a common pattern:\n\n```\n~/src/oascomply % oascomply -x -f tutorial/references/openapi.json -f tutorial/references/pathitems/foo.json -f tutorial/references/schemas/bar.json\nERROR:oascomply.apidescription:JSON Schema documents must pass \"Schema\" (without quotes) as an additional -f argument:\n\n\t -x -f tutorial/references/schemas/bar.json Schema\n```\n\nOK, we're closer.  This example has a standalone schema file, and for Reasons™\n(meaning that the author ran out of time to fix it before this milestone),\n`oascomply` gets a bit confused.  But at least it tells you how to fix it!\nSo let's try that:\n\n```\n~/src/oascomply % oascomply -x -f tutorial/references/openapi.json -f tutorial/references/pathitems/foo.json -f tutorial/references/schemas/bar.json Schema\nYour API description is valid!\n```\n\n### Verbose validation and nicer URIs\n\nNow it works!  But as you can see in the errors from earlier, the URI is just\na `file:` URL with the `.json` chopped off, which is... kinda misleading.\nThe reason API description authors usually leave off the `.json` or `.yaml`\nis because the documents will be made available over HTTPS, and the JSON\nvs YAML format will be handled in content negotiation.  We can assign\n`https:` URIs instead of `file:` ones (but the URLs will always be `file:`\nURLs, at least until support for validating remote descriptions is added).\n\nThe simplest way to do that is to put the URI after the file as part\nof the `-f` option.  Let's also increase the verbosity by passing `-v`,\nwhich will show us the URIs without needing to provoke an error message:\n\n```\n~/src/oascomply % oascomply -f tutorial/minimal.json https://example.com/minimal -v\nINFO:oascomply.apidescription:Adding document \"tutorial/minimal.json\" ...\nINFO:oascomply.apidescription:...URL \u003cfile:///Users/handrews/src/oascomply/tutorial/minimal.json\u003e\nINFO:oascomply.apidescription:...URI \u003chttps://example.com/minimal\u003e\nINFO:oascomply.apidescription:...instantiating OAS Document \u003chttps://example.com/minimal\u003e\nINFO:oascomply.apidescription:Checking JSON Schema references in \u003chttps://example.com/minimal#\u003e...\nINFO:oascomply.apidescription:...resolving with OasJson.resolve_references()\nYour API description is valid!\n```\n\nHere we get some information, including how URLs and URIs are associated.\n\nSetting the URI for each file like that is fine when you only have one file,\nbut it can get annoying with more.  The `-d` option lets you associate\na directory with a URI prefix.  `oascomply` will replace the directory with\nthe prefix to create the URI, and strip off any file extension automatically.\nThere is no need to pass `-x` with `-d`, and the format is similar to `-f` —\nfirst the filesystem path, then the URI (or URI prefix in this case):\n\n```\n~/src/oascomply % oascomply -d tutorial/references https://example.com -f tutorial/references/openapi.json -f tutorial/references/pathitems/foo.json -f tutorial/references/schemas/bar.json Schema -v\nERROR:oascomply.apidescription:URI prefixes must include a path that ends with '/': \u003ctutorial/references\u003e\n```\n\nOops!  URI prefixes need to end with a `/` to match the directory, otherwise\nthe behavior gets a little confusing.  But that's easily fixed:\n\n```\n~/src/oascomply % oascomply -d tutorial/references https://example.com/ -f tutorial/references/openapi.json -f tutorial/references/pathitems/foo.json -f tutorial/references/schemas/bar.json Schema -v\nINFO:oascomply.apidescription:Adding document \"tutorial/references/openapi.json\" ...\nINFO:oascomply.apidescription:...URL \u003cfile:///Users/handrews/src/oascomply/tutorial/references/openapi.json\u003e\nINFO:oascomply.apidescription:...URI \u003chttps://example.com/openapi\u003e\nINFO:oascomply.apidescription:...instantiating OAS Document \u003chttps://example.com/openapi\u003e\nINFO:oascomply.apidescription:Adding document \"tutorial/references/pathitems/foo.json\" ...\nINFO:oascomply.apidescription:...URL \u003cfile:///Users/handrews/src/oascomply/tutorial/references/pathitems/foo.json\u003e\nINFO:oascomply.apidescription:...URI \u003chttps://example.com/pathitems/foo\u003e\nINFO:oascomply.apidescription:...instantiating OAS Document \u003chttps://example.com/pathitems/foo\u003e\nINFO:oascomply.apidescription:Adding document \"tutorial/references/schemas/bar.json\" ...\nINFO:oascomply.apidescription:...URL \u003cfile:///Users/handrews/src/oascomply/tutorial/references/schemas/bar.json\u003e\nINFO:oascomply.apidescription:...URI \u003chttps://example.com/schemas/bar\u003e\nINFO:oascomply.apidescription:...instantiating JSON Schema \u003chttps://example.com/schemas/bar\u003e\nINFO:oascomply.apidescription:Checking JSON Schema references in \u003chttps://example.com/openapi#\u003e...\nINFO:oascomply.apidescription:...resolving with OasJson.resolve_references()\nINFO:oascomply.apidescription:Checking JSON Schema references in \u003chttps://example.com/pathitems/foo#\u003e...\nINFO:oascomply.apidescription:...resolving with OasJson.resolve_references()\nINFO:oascomply.apidescription:Checking JSON Schema references in \u003chttps://example.com/schemas/bar\u003e...\nINFO:oascomply.apidescription:...already resolved by jschon.JSONSchema()\nINFO:oascomply.oasgraph:Validating \"example\" https://example.com/openapi#/example against schema https://example.com/openapi#/components/responses/foo/content/application~1json/schema, metaschema https://spec.openapis.org/oas/v3.0/dialect/base\nINFO:oascomply.oasgraph:Validating \"example\" https://example.com/schemas/bar#/example against schema https://example.com/schemas/bar, metaschema https://spec.openapis.org/oas/v3.0/dialect/base\nINFO:oascomply.oasgraph:Validating \"default\" https://example.com/schemas/bar#/default against schema https://example.com/schemas/bar, metaschema https://spec.openapis.org/oas/v3.0/dialect/base\nINFO:oascomply.oasgraph:Validating \"example\" https://example.com/openapi#/example against schema https://example.com/openapi#/components/responses/foo/content/application~1json/schema, metaschema https://spec.openapis.org/oas/v3.0/dialect/base\nINFO:oascomply.oasgraph:Validating reference \u003chttps://example.com/openapi#/paths/~1foo/$ref\u003e to \u003chttps://example.com/pathitems/foo\u003e\nINFO:oascomply.oasgraph:Validating reference \u003chttps://example.com/openapi#/components/responses/foo/content/application~1json/schema/$ref\u003e to \u003chttps://example.com/openapi#/components/schemas/bar\u003e\nINFO:oascomply.oasgraph:Validating reference \u003chttps://example.com/openapi#/components/responses/foo/links/self/operationRef\u003e to \u003chttps://example.com/pathitems/foo#/get\u003e\nINFO:oascomply.oasgraph:Validating reference \u003chttps://example.com/openapi#/components/schemas/bar/$ref\u003e to \u003chttps://example.com/schemas/bar#\u003e\nINFO:oascomply.oasgraph:Validating reference \u003chttps://example.com/pathitems/foo#/get/responses/200/$ref\u003e to \u003chttps://example.com/openapi#/components/responses/foo\u003e\nYour API description is valid!\n```\n\nThis multi-document example also uses the `example` and `default` keywords, so we get informed that the values of those keywords are being validated against their schemas.  This validation supports OAS 3.0-specific keywords like `nullable`, and also validates some `format`s (currently only certain string formats, but more will be added).  Validation of examples and defaults can be disabled by passing `-e false`.\n\nWe also see at the end that there is some additional validation of references, which checks that the type of the reference target matches what the reference source expects.\n\n## Displaying the parsed graph\n\nGetting a yes or no for validation is nice, and we'll look at the error\noutput for the \"no\" case further down.  But what else does this tool do?\n\nIt constructs an RDF (Resource Description Framework 1.1) graph out of the API description.\nThis is somewhat analogous to how compilers parse programming languages\ninto an abstract syntax tree.  Don't worry, you don't need to go read\nthe RDF spec (or the endless number of related semantic web specs) to\nbenefit from this graph!\n\nWe need to build a graph rather than a tree in order to show how references\nconnect different pieces of the description documents.  In later milestones\nwe will also use this graph to do much more sophisticated validation.\n\nThere are many ways to write an RDF graph to a file, and `oascomply` can\nproduce any of the ones supported by the Python `rdflib` package.  But the\ndefault, which you get by passing `-o` without an argument, is a simple\nline-oriented format known as\n[N-Triples 1.1](https://www.w3.org/TR/n-triples/).  It is supported by\nmost RDF-based tools, but is also simple enough to be parsed directly\nby a regular expression, which can be found in the `oascomply.reparse` module.\n\nTo print the graph to stdout, use the `-o` option without an argument.\nHere, we redirect it to a `.nt` file, which is the standard N-Triples\nfile extension (diagnostic messages such as\n\"Your API description is valid!\" are printed to stderr).  We'll set a short\nHTTPS URI as it's less noisy than full filesystem paths:\n\n```\n~/src/oascomply % oascomply -f tutorial/minimal.json https://example.com/minimal -o \u003e minimal.nt\nYour API description is valid!\n```\n\nLet's take a look at that output file:\n\n```TTL\n\u003chttps://example.com/minimal#\u003e \u003chttps://spec.openapis.org/compliance/ontology#paths\u003e \u003chttps://example.com/minimal#/paths\u003e .\n\u003chttps://example.com/minimal#/info\u003e \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"Info\" .\n\u003chttps://example.com/minimal\u003e \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"minimal.json\" .\n\u003chttps://example.com/minimal\u003e \u003chttps://spec.openapis.org/compliance/ontology#locatedAt\u003e \"file:///Users/handrews/src/oascomply/tutorial/minimal.json\"^^\u003chttp://www.w3.org/2001/XMLSchema#anyURI\u003e .\n\u003chttps://example.com/minimal\u003e \u003chttps://spec.openapis.org/compliance/ontology#root\u003e \u003chttps://example.com/minimal#\u003e .\n\u003chttps://example.com/minimal#/info\u003e \u003chttps://spec.openapis.org/compliance/ontology#allowsExtensions\u003e \"true\"^^\u003chttp://www.w3.org/2001/XMLSchema#boolean\u003e .\n\u003chttps://example.com/minimal#/info\u003e \u003chttps://spec.openapis.org/compliance/ontology#parent\u003e \u003chttps://example.com/minimal#\u003e .\n\u003chttps://example.com/minimal#/info\u003e \u003chttps://spec.openapis.org/compliance/ontology#title\u003e \"Minimal OAS 3.0 description\" .\n\u003chttps://example.com/minimal#/info\u003e \u003chttp://www.w3.org/1999/02/22-rdf-syntax-ns#type\u003e \u003chttps://spec.openapis.org/compliance/ontology#3.0-Info\u003e .\n\u003chttps://example.com/minimal#\u003e \u003chttps://spec.openapis.org/compliance/ontology#allowsExtensions\u003e \"true\"^^\u003chttp://www.w3.org/2001/XMLSchema#boolean\u003e .\n\u003chttps://example.com/minimal#/paths\u003e \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"Paths\" .\n\u003chttps://example.com/minimal#/paths\u003e \u003chttps://spec.openapis.org/compliance/ontology#allowsExtensions\u003e \"true\"^^\u003chttp://www.w3.org/2001/XMLSchema#boolean\u003e .\n\u003chttps://example.com/minimal#/info\u003e \u003chttps://spec.openapis.org/compliance/ontology#apiDescriptionVersion\u003e \"1.0.0\" .\n\u003chttps://example.com/minimal\u003e \u003chttp://www.w3.org/1999/02/22-rdf-syntax-ns#type\u003e \u003chttps://schema.org/DigitalDocument\u003e .\n\u003chttps://example.com/minimal#\u003e \u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e \"OpenAPI\" .\n\u003chttps://example.com/minimal#/paths\u003e \u003chttps://spec.openapis.org/compliance/ontology#parent\u003e \u003chttps://example.com/minimal#\u003e .\n\u003chttps://example.com/minimal#\u003e \u003chttps://spec.openapis.org/compliance/ontology#info\u003e \u003chttps://example.com/minimal#/info\u003e .\n\u003chttps://example.com/minimal#\u003e \u003chttp://www.w3.org/1999/02/22-rdf-syntax-ns#type\u003e \u003chttps://spec.openapis.org/compliance/ontology#3.0-OpenAPI\u003e .\n\u003chttps://example.com/minimal#/paths\u003e \u003chttp://www.w3.org/1999/02/22-rdf-syntax-ns#type\u003e \u003chttps://spec.openapis.org/compliance/ontology#3.0-Paths\u003e .\n\u003chttps://example.com/minimal#\u003e \u003chttps://spec.openapis.org/compliance/ontology#oasVersion\u003e \"3.0.3\" .\n```\n\nThat's easy for machines to parse but a bit hard for people to read.\nWhile there are RDF serialization formats that try to be human-friendly,\nthey don't work well with JSON Pointer fragments.  The `-o` option can\ntake a format identifer (such as `-o ttl` for Turtle or `-o json-ld` for\nJSON-LD) for any format supported by\n[`rdflib`](https://rdflib.readthedocs.io/en/stable/).  But it also offers\na custom TOML format (`-o toml`) meant for human-friendly output:\n\n```TOML\n[namespaces]\nrdf = \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\nrdfs = \"http://www.w3.org/2000/01/rdf-schema#\"\nxsd = \"http://www.w3.org/2001/XMLSchema#\"\nschema = \"https://schema.org/\"\noas = \"https://spec.openapis.org/compliance/ontology#\"\n\"oas3.0\" = \"https://spec.openapis.org/compliance/ontology#3.0-\"\n\n[\"https://example.com/minimal\"]\n\"rdf:type\" = \"schema:DigitalDocument\"\n\"rdfs:label\" = [ \"minimal.json\",]\n\"oas:locatedAt\" = [ \"file:///Users/handrews/src/oascomply/tutorial/minimal.json\", \"xsd:anyURI\",]\n\"oas:root\" = \"https://example.com/minimal#\"\n\n[\"https://example.com/minimal#\"]\n\"rdf:type\" = \"oas3.0:OpenAPI\"\n\"rdfs:label\" = [ \"OpenAPI\",]\n\"oas:allowsExtensions\" = [ \"true\", \"xsd:boolean\",]\n\"oas:info\" = \"https://example.com/minimal#/info\"\n\"oas:oasVersion\" = [ \"3.0.3\",]\n\"oas:paths\" = \"https://example.com/minimal#/paths\"\n\n[\"https://example.com/minimal#/info\"]\n\"rdf:type\" = \"oas3.0:Info\"\n\"rdfs:label\" = [ \"Info\",]\n\"oas:allowsExtensions\" = [ \"true\", \"xsd:boolean\",]\n\"oas:apiDescriptionVersion\" = [ \"1.0.0\",]\n\"oas:parent\" = \"https://example.com/minimal#\"\n\"oas:title\" = [ \"Minimal OAS 3.0 description\",]\n\n[\"https://example.com/minimal#/paths\"]\n\"rdf:type\" = \"oas3.0:Paths\"\n\"rdfs:label\" = [ \"Paths\",]\n\"oas:allowsExtensions\" = [ \"true\", \"xsd:boolean\",]\n\"oas:parent\" = \"https://example.com/minimal#\"\n```\n\nKeep in mind that for programmatic use, libraries like Python's\n[`rdflib`](https://rdflib.readthedocs.io/en/stable/) can parse N-Triples\ndirectly and offer far more powerful features for working with the data.\n\nThis TOML format is intended purely for human convenience, and is somewhat\nexperimental.  Feedback is encouraged!\n\nWe'll talk more about namespaces and how this condensed format works further\ndown, but lets dig into the N-Triples format first.\n\n## Reading the N-Triples output\n\nN-Triples may look like a bit of a mess with all of the URIs, but it's\nreally pretty straightforward.  Each line represents an RDF triple, which\nis an edge connecting two nodes in the graph:\n\n* Concepts, including data types, relationships, OAS object types (Path Item Object, Schema Object, etc.), and the actual typed objects from your API description, are represented by URIs in angle brackets.\n* Literal values, such as OAS object properties from your API description, are quoted strings.\n* Literals with a data type other than a plain string are followed by `^^` and a URI in angle brackets indicating the type.\n\nEdges are unidirectional, from the concept on the left (the _subject_)\nto the concept or literal on the right (the _object_).  The URI in the\nmiddle is called the _predicate_, and describes the relationship\nrepresented by the edge (I'll just call it the _relationship_ from here on).\n\nThis will likely make more sense with a picture.\nHere is an image showing the exact data displayed above:\n\n![visualization of minimal.json graph](tutorial/minimal.png)\n\nThis visualization does not show the literal values (the tool used to\ngenerate it shows them in a side panel when you click on a node).\n\n### Line by line\n\nEvery N-Triples line looks like one of the following three structures:[^lang]\n\n```TTL\n\u003csubject_concept\u003e \u003crelationship\u003e \u003cobject_concept\u003e .\n\u003csubject_concept\u003e \u003crelationship\u003e \"string literal value\" .\n\u003csubject_concept\u003e \u003crelationship\u003e \"literal value\"^^\u003cdatatype\u003e .\n```\n\nThe `.` terminates the line, and is mostly there to make this format\na valid subset of several more complex formats.\n\nSince the same node can appear in either the subject or object position in\nmany triples, these lines in the output connect through shared nodes to form\na graph:\n\n```TTL\n\u003ca\u003e \u003cx\u003e \u003cb\u003e .\n\u003cb\u003e \u003cy\u003e \u003cc\u003e .\n\u003ca\u003e \u003cz\u003e \"d\" .\n```\n\nThis is a graph with three nodes, `\u003ca\u003e`, `\u003cb\u003e`, and `\u003cc\u003e`, with edges\n`\u003cx\u003e` connecting `\u003ca\u003e` to `\u003cb\u003e`, and `\u003cy\u003e` connecting `\u003cb\u003e` to `\u003cc\u003e`.\nNode `\u003ca\u003e` is also connected to a literal string \"d\" by edge `\u003cz\u003e`.[^prop]\n\n### Seeing through the URI clutter\n\nRDF-aware tools are good at making use of the full URIs behind the scenes,\nbut if you're reading the output directly, it's a bit much.\n\nIn most cases, the absolute URI (the part before the `#`) serves as\na namespace, and the URI fragment (the part after the `#`)\nidentifies a specific thing within that namespace.\n\nHere are the namespaces you will see in in `oascomply` output\nin addition to the URI (which is by default the `file:` URL for local files)\nof your own document.  It is typical to include the trailing `#` as part of\nthe namespace.[^namespaces]\n\nFirst, the namespaces defined outside of OpenAPI:\n\n* `http://www.w3.org/2001/XMLSchema#` – XSD, which is used for its datatype definitions; no actual understanding of XML Schema is required!\n* `http://www.w3.org/1999/02/22-rdf-syntax-ns#` – RDF, which defines fundamental concepts and relationships such as the `type` relationship; you will notice this relationship connecting locations in your file to their OAS Object types\n* `http://www.w3.org/2000/01/rdf-schema#` – RDFS (RDF Schema), which includes a few more fairly fundamental concepts and relationships; the distinction between RDF and RDFS is not very important here, and `oascomply` mostly just uses the `label` relationship which informs tools how to display nodes for humans\n* `https://schema.org/` – Schema.org defines many common concepts; currently `oascomply` just uses the \"DigitalDocument\" concept (note that values in this namespace are part of the URI path, not the fragment)\n\nOpenAPI concepts use the following namespace:\n\n* `https://spec.openapis.org/compliance/ontology#`\n\nFor OpenAPI object types, a version prefix, e.g. `3.0-Schema`, is part of the fragment.  For relationships, including object fields with string, number, or boolean values, there is no version prefix.  _(This may not remain the case, it will depend on feedback).\n\n## Reading the experimental TOML output\n\nThe TOML output format is an experiment in providing something a little\nmore intuitive.  Here's a portion of the earlier example for reference:\n\n```TOML\n[namespaces]\nrdf = \"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\nrdfs = \"http://www.w3.org/2000/01/rdf-schema#\"\nxsd = \"http://www.w3.org/2001/XMLSchema#\"\nschema = \"https://schema.org/\"\noas = \"https://spec.openapis.org/compliance/ontology#\"\n\"oas3.0\" = \"https://spec.openapis.org/compliance/ontology#3.0-\"\n\n[\"https://example.com/minimal\"]\n\"rdf:type\" = \"schema:DigitalDocument\"\n\"rdfs:label\" = [ \"minimal.json\",]\n\"oas:locatedAt\" = [ \"file:///Users/handrews/src/oascomply/tutorial/minimal.json\", \"xsd:anyURI\",]\n\"oas:root\" = \"https://example.com/minimal#\"\n```\n\nCurrently the format is as follows:\n\n* The first section, `[namespaces]`, defines the short names for each namespace, and the URI prefix the short name represents\n* The remaining section headings are subjects in the RDF triples\n* Under each heading, the keys are predicates (relationships) and the values are objects, forming a triple with the subject in the heading\n* String literal object values are one-element arrays\n* Typed literal object values are two-element arrays, with the datatype as the second element\n* Multiple objects for the same subject and predicate appear as arrays\n\nWhile the two different uses of arrays is somewhat ambiguous for the two-element array case, in practice datatypes tend to be very recognizable.  However, feedback on this is encouraged.\n\n## Understanding error messages\n\nUser-friendly error reporting is the focus of Milestone 2, which is\nplanned to be complete in mid-July, 2023.  Currently, errors are\nreported in whatever structure is returned by whatever library\nencountered the error, or whatever structure seemed most convenient.\nAnd sometimes there's just a stack trace.\n\nRest assured that this is not considered good UX/DX.  In the\nmeantime, here are some current ways errors are reported.\n\n### No `openapi` field\n\n`oascomply` looks for an `openapi` field in the root object of\nat least one of the documents it is passed.  The first document\nin the argument list containing the field is the API description\nthat is validated.  If no documents contain an `openapi` field,\nthe program ends after logging an error:\n\n```\n~/src/oascomply -f tutorial/invalid/no-openapi.json\nERROR:oascomply.apidescription:No document contains an 'openapi' field!\n```\n\n### JSON Schema validation errors\n\nThe first step `oascomply` performs is validation with the patched\nversion of the OAS JSON Schema.  The patches can be found in the\n`patches/oas/v3.0` directory in this repository.  They are applied\nto the OAS schema found under\n`submodules/OpenAPI-Specification/schemas/v3.0` prior to each\nmilestone release, and the results checked in under the\n`schemas/oas/v3.0` directory.\n\nJSON Schema validation errors are reporting using the\n[\"detailed\" standard output format](https://www.ietf.org/archive/id/draft-bhutton-json-schema-01.html#name-detailed):\n\n```\n~/src/oascomply % oascomply -f tutorial/invalid/no-info.json\nCRITICAL:oascomply.apidescription:JSON Schema validation of file:///Users/handrews/src/oascomply/tutorial/invalid/no-info.json failed!\n\n{\n  \"valid\": false,\n  \"instanceLocation\": \"\",\n  \"keywordLocation\": \"\",\n  \"absoluteKeywordLocation\": \"https://spec.openapis.org/compliance/schemas/oas/3.0/2023-06#\",\n  \"errors\": [\n    {\n      \"instanceLocation\": \"\",\n      \"keywordLocation\": \"/required\",\n      \"absoluteKeywordLocation\": \"https://spec.openapis.org/compliance/schemas/oas/3.0/2023-06#/required\",\n      \"error\": \"The object is missing required properties ['info']\"\n    }\n  ]\n}\n```\n\n### Examples and defaults validation errors\n\nExample and default values are validated against the relevant schemas,\nand report any errors in those validations in the same format.  In this\nexample, there are errors from two distinct validation processes:\none for a `\"default\"` in a Parameter Object, and one for an `\"example\"`\nin a Media Type Object:\n\n```\n~/src/oascomply % oascomply -f tutorial/invalid/examples.yaml\nERROR:oascomply.apidescription:{\n  \"valid\": false,\n  \"instanceLocation\": \"/paths/~1things/get/parameters/0/schema/default\",\n  \"keywordLocation\": \"\",\n  \"absoluteKeywordLocation\": \"file:/Users/handrews/src/oascomply/tutorial/invalid/examples.yaml#/paths/~1things/get/parameters/0/schema\",\n  \"errors\": [\n    {\n      \"instanceLocation\": \"/paths/~1things/get/parameters/0/schema/default\",\n      \"keywordLocation\": \"/format\",\n      \"absoluteKeywordLocation\": \"file:/Users/handrews/src/oascomply/tutorial/invalid/examples.yaml#/paths/~1things/get/parameters/0/schema/format\",\n      \"error\": \"The instance is invalid against the \\\"uint8\\\" format: -1 is outside of uint8 range\"\n    }\n  ]\n}\nERROR:oascomply.apidescription:{\n  \"valid\": false,\n  \"instanceLocation\": \"/paths/~1things/get/responses/200/content/application~1json/example\",\n  \"keywordLocation\": \"\",\n  \"absoluteKeywordLocation\": \"file:/Users/handrews/src/oascomply/tutorial/invalid/examples.yaml#/paths/~1things/get/responses/200/content/application~1json/schema\",\n  \"errors\": [\n    {\n      \"instanceLocation\": \"/paths/~1things/get/responses/200/content/application~1json/example\",\n      \"keywordLocation\": \"/format\",\n      \"absoluteKeywordLocation\": \"file:/Users/handrews/src/oascomply/tutorial/invalid/examples.yaml#/paths/~1things/get/responses/200/content/application~1json/schema/format\",\n      \"error\": \"The instance is invalid against the \\\"uri\\\" format: '/foo/bar' is not a valid 'URI'.\"\n    }\n  ]\n}\n\nAPI description contains errors\n```\n\nNote that these errors come from the `\"format\"` keyword.  While not all standard\nformat values are supported yet, many are, and the remainder will be added\nduring Milestone 2.\n\n### Errors from semantic validation of references\n\nSemantic validation using the RDF graph produce by the parser\nis the focus of Milestone 3, which is expected in late August 2023.\nCurrently, a very simple example of using the graph for validation\nis implemented in the form of checking that reference targets\nare of the correct type.\n\nIn this example, a $ref for a Path Item Object points to\na Schema Object.  This cannot be detected just by validating the\nreference target against a JSON Schema because both a Path Item Object\nand a Schema Object can be empty objects.  However, the parsed graph\nincludes the information that objects under `#/components/schemas`\nare Schema Objects:\n\n```\n~/src/oascomply % oascomply -f tutorial/invalid/wrong-ref-type.yaml\nERROR:oascomply.apidescription:{\n  \"json_reference\": \"file:///Users/handrews/src/oascomply/tutorial/invalid/wrong-ref-type.yaml#/paths/~1stuff/$ref\",\n  \"reference_context\": {\n    \"node\": \"file:///Users/handrews/src/oascomply/tutorial/invalid/wrong-ref-type.yaml#/paths/~1stuff\"\n  },\n  \"reference_target\": \"file:///Users/handrews/src/oascomply/tutorial/invalid/wrong-ref-type.yaml#/components/schemas/stuff\",\n  \"expected\": [\n    \"file:///Users/handrews/src/oascomply/tutorial/invalid/wrong-ref-type.yaml#/components/schemas/stuff\",\n    \"http://www.w3.org/1999/02/22-rdf-syntax-ns#type\",\n    \"https://spec.openapis.org/compliance/ontology#3.0-PathItem\"\n  ],\n  \"actual\": [\n    \"file:///Users/handrews/src/oascomply/tutorial/invalid/wrong-ref-type.yaml#/components/schemas/stuff\",\n    \"http://www.w3.org/1999/02/22-rdf-syntax-ns#type\",\n    \"https://spec.openapis.org/compliance/ontology#3.0-Schema\"\n  ]\n}\n\nAPI description contains errors\n```\n\nHere we see information about which reference has the error, and then the\nexpected and actual type information as semantic triples.\nThe subject of each triple is the reference target location, the predicate\n(relationship) is the standard RDF:type relationship, and the object\ngives the type in the OAS namespace.  Here we can see that we expected\nas `3.0-PathItem` but found a `3.0-Schema`.\n\n## Standalone validation with OAS 3.0-dialect JSON Schemas\n\nThe `oascomply.oas30dialect` package adds support for the OAS 3.0\nschema dialect for the Python package `jschon`.  The `oas30-schema`\ncommand line tool uses that module to validate a given instance\nagainst an OAS 3.0-compliant Schema Object schema, and optionally\nproduce annotation output in any of the JSON Schema draft 2020-12\nstandard output formats (even though the OAS 3.0 dialect is\nbased on JSON Schema draft-04):\n\n```\n~/src/oascomply % oas30-schema -h\nusage: oas30-schema [-h] [-r REFS] [-o [{basic,detailed,verbose}]]\n                    [-e {basic,detailed,verbose}]\n                    instance schema\n\nValidates the instance against schemas using the OAS 3.0 Schema Object dialect\ndescribed by the metaschema \"{OAS30_DIALECT_METASCHEMA}\"\n\npositional arguments:\n  instance              The JSON or YAML file to validate\n  schema                The schema, in JSON or YAML format, to use\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -r REFS, --referenced-schema REFS\n                        NOT YET SUPPORTED! An additional schema from which to\n                        resolve references; can be passed multiple times; note that\n                        schema documents that reference each other are not currently\n                        supported; currently, if schema A references schema B, then\n                        schema B must be passed with -r *BEFORE* schema A\n  -o [{basic,detailed,verbose}], --output [{basic,detailed,verbose}]\n                        On success, print the annotation output to stdout using the\n                        given standard format; the default annotation format is\n                        'basic'\n  -e {basic,detailed,verbose}, --error-format {basic,detailed,verbose}\n                        Set the output format to use for error reporting; the\n                        default format is 'detailed'\n\nNote that the schema \"https://spec.openapis.org/oas/v3.0/dialect/base\" is *NOT*\nprovided by the OpenAPI Initiative, but is part of the oascomply package\n```\n-----\n\n[^namespaces]: In more complex RDF formats, namespaces are displayed\nas short names that substitute for a URI prefix (technically an IRI\nprefix, but that just means URI with unicode support).  You can see\nthis by passing `-o ttl` which produces the relatively human-readable\nTurtle format.  It will include things like `rdfs:label` in place of\n`\u003chttp://www.w3.org/2000/01/rdf-schema#label\u003e`.  Unfortunately, when\nusing these short prefixes, many characters used in JSON Pointer\nfragments, including `/` and `$`, are not allowed.  This means most URIs\nfor your API description end up written out in full, making the prefix\nconcept less useful than it really should be.  N-Triples was selected\nin part to avoid confusion around this.\n\n[^lang]: There is a fourth structure used for language-tagged strings, but\n`oascomply` is not currently aware of what (human, not programming) language\nan API description uses, so this structure does not appear in the output.\n\n[^prop]: If you are familiar with property graphs, which are another type of\ngraph database, literal nodes are roughly equivalent to properties\nin property graphs (although RDF refers to all edges as properties).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foai%2Foascomply","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foai%2Foascomply","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foai%2Foascomply/lists"}