Repository navigation
Rewrite the OpenAPI document to describe the Elasticsearch service, and make the endpoints match it - #42
Closed
gaurav wants to merge 24 commits into
Closed
Rewrite the OpenAPI document to describe the Elasticsearch service, and make the endpoints match it#42gaurav wants to merge 24 commits into
gaurav wants to merge 24 commits into
Conversation
gaurav
marked this pull request as draft
October 5, 2026 23:12
The document was copied from NodeNorm Redis and never pruned, so it advertised TRAPI 1.5 (info.x-trapi), carried 145 schemas no path referenced, named RENCI's developer as the contact and sent readers to /get_curie_prefixes, which this service has never served. It also failed openapi-spec-validator: the /get_allowed_conflations response had no description, and FilterKgraphTopNParameters.max_edges declared maximum 0 (NCATSTranslator/NodeNormalization#409). Rewritten from scratch against build_handlers(): the six routes this service registers, nothing else. Responses that were `schema: {}` now have schemas (NormalizedNodes, SetIDResponse), the FastAPI 422 responses are replaced by the 400 the Tornado handlers raise, and the examples are taken from the live CI instance. The servers block lists the ci and test deployments at ITRB instead of RENCI. Contact is Will Liu and the team is DOGSURF (biothings#35); infores and termsOfService are unchanged for now. info.version is bumped to 1.1.0 because /status reports it and the response shapes change in the next commit. handlers/curie_prefix.py was an unregistered copy of the semantic-types handler (its class is even named SemanticTypeHandler), so it goes too. Refs biothings#35, biothings#36 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GET /get_allowed_conflations finished a bare list, and Tornado's write()
refuses a top-level list ("Lists not accepted for security reasons"),
so it returned HTTP 500 on every deployment. It now returns
{"conflations": [...]}, which is also what NodeNorm Redis returns.
GET /get_semantic_types lower-cased every class ("biolink:namedthing");
NodeNorm Redis returns the Biolink class URI as is ("biolink:NamedThing").
/openapi.json now redirects to /webapp/openapi.json so the FastAPI
default address used by NodeNorm Redis, SmartAPI and Babel Validation
works here too; it is excluded from OpenTelemetry like the other static
paths.
The POST set-ID test posted a single object where the handler expects
a list of sets, and the normalized-nodes docstring showed a "curie" key
where the handler reads "curies"; both corrected. POST /get_setid still
answers with an object keyed "0", "1", ... (the same Tornado limitation);
returning a list as NodeNorm Redis does is a breaking change, so it is
left to its own pull request.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The document is hand-written and served as a static file, so these tests are what stops it drifting: the spec validates; its paths are exactly the routes build_handlers() registers; each path documents the GET/POST methods its handler defines; each GET documents the query parameters its handler reads (found by scanning the handler source for get_argument calls); and the SetIDResponse schema lists the dataclass's fields. Each was checked to fail when the spec is mutated. Also a regression test for /get_allowed_conflations, which returned HTTP 500 until the previous commit: it mounts just that handler and validates the body against the documented ConflationList schema. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
It ran only against the su10 Elasticsearch host before. This mounts the handler alone with a fake Elasticsearch client and validates the body against the documented schema. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The dot in each redirect pattern was unescaped, so /openapiXjson and /faviconXico redirected too. The OpenTelemetry exclusions already escape it. A test now checks the /openapi.json redirect and that a near-miss path is a 404. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ment
The query-parameter check scanned only get() for get_argument calls, so
a parameter read in a helper method would drift unnoticed; it now scans
the whole handler class. A new check compares the fields each post()
reads with .get("...") against the properties of the documented request
body (CurieList, and the SetIDQuery items of the /get_setid array).
Both were confirmed to fail when a field is removed from the document or
a parameter is renamed in a helper.
The checks still only see literal names; the README now says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gaurav
force-pushed
the
update-openapi-spec
branch
from
October 12, 2026 05:08
0daf631 to
e6a1673
Compare
generate_setid() returned the SetIDResponse dataclass itself on the invalid-conflation and no-normalized-CURIEs paths. Tornado can only write dicts, so GET /get_setid?conflation=Bogus answered 500 and the documented `error` field never reached anyone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The body has to be a JSON array of {curies, conflations} objects. A
single object (the shape the old document described) passed the length
check and then failed with an AttributeError, and invalid JSON failed in
json.loads; both were 500s. They are now 400s that say what shape the
body must have.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The index mapping (for the Babel version) was read before the try
block, so an unreachable cluster raised and /status answered 500
instead of the documented {"status": "error"}. The read now happens
inside the try; babel_version and babel_version_url are null when the
mapping couldn't be read, and the document says so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The patterns were written r"/get_setid?", r"/status?" and so on. In a Tornado route that ? makes the last character optional, so /get_seti and /statu reached the handlers though the OpenAPI document lists only the full paths. test_openapi.py hid this by stripping the ? before comparing routes with the document; it now compares them as written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The request-body check read only post()'s source, though the README says fields are found by scanning the handler, and the query-parameter check already scans the whole class. A body field read in a helper method was either missed or reported as undocumented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The methods check compared only GET and POST, so the HEAD handler on /get_allowed_conflations, which the document didn't list, went unnoticed. It now compares every method Tornado routes except OPTIONS (answered by the base handler for CORS), and the document lists HEAD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/test_openapi.py imports it directly; it was only installed because openapi-spec-validator happens to depend on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
parse_boolean() treated every string except "false" as true, so
conflate=0 or conflate=no turned conflation on. The flags now accept the
strings FastAPI/Pydantic accepted in NodeNorm Redis (true/false, 1/0,
yes/no, on/off, t/f, y/n, in any case) and answer 400 for anything else,
including an empty value. POST bodies go through the same check, so
{"conflate": "false"} is no longer truthy. The document lists the
accepted values.
This is a behavior change: a caller sending an unrecognized value now
gets a 400 where it used to get conflation silently switched on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Covers the second path biothings#47 describes: a set whose CURIEs normalize to nothing. get_normalized_nodes() is patched out, so it needs no host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
https://nodenorm-es.transltr.io/ is now live. It goes first, since Swagger UI and generated clients default to the first server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Request schemas conflict with runtime behavior, malformed UTF-8 can still produce HTTP 500, and the contact remains unresolved.
2 open findings
What changed in this PR
Rewrites the OpenAPI specification to reflect the Elasticsearch-backed service and aligns endpoint behavior with the documented contract.
Changes:
- Replaces obsolete TRAPI documentation with six current routes and schemas.
- Fixes route matching, status handling, boolean parsing, conflations, semantic types, and set-ID errors.
- Adds contract and regression tests.
| File | Description |
|---|---|
README.md |
Documents OpenAPI maintenance. |
docker/configuration/config.json |
Excludes OpenAPI redirect from telemetry. |
pyproject.toml |
Adds schema-validation test dependencies. |
src/nodenorm/config/config.default.json |
Updates telemetry exclusions. |
src/nodenorm/handlers/__init__.py |
Fixes routes and adds redirect. |
src/nodenorm/handlers/conflations.py |
Returns a documented object response. |
src/nodenorm/handlers/curie_prefix.py |
Removes an unused handler. |
src/nodenorm/handlers/health.py |
Handles unavailable Elasticsearch. |
src/nodenorm/handlers/normalized_nodes.py |
Adds strict boolean parsing. |
src/nodenorm/handlers/semantic_types.py |
Preserves Biolink class casing. |
src/nodenorm/handlers/set_identifiers.py |
Validates bodies and serializes errors. |
src/nodenorm/webapp/openapi.json |
Rewrites the API specification. |
tests/test_openapi.py |
Adds contract and regression coverage. |
tests/test_set_identifiers.py |
Updates POST request and response expectations. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
json.loads() raises UnicodeDecodeError rather than JSONDecodeError for bytes that aren't valid UTF-8, so such a body escaped the check and became a 500, though the document promises a 400 for a malformed body. The decoding moves to a load_json_body() helper on the base handler so POST /get_normalized_nodes can use it too. Raised by Copilot on biothings#42. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The handler called json.loads() with no error handling and then .get() on the result, so a body that wasn't JSON, wasn't UTF-8, or was an array instead of an object all became 500s. It now uses load_json_body() and checks for an object, and the document lists these under the 400 response. Same cause as the UTF-8 case Copilot raised for POST /get_setid on biothings#42. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gaurav
added a commit
to TranslatorSRI/NodeNormalizationAPI
that referenced
this pull request
Oct 14, 2026
This commit used to add the POST /get_setid body checks themselves: a body that wasn't valid JSON, was a single object, or held anything other than objects reached group.get() and failed with HTTP 500. biothings#42 now makes those checks (through load_json_body()) and tests them, so after rebasing onto it all that is left is the empty-body case, which its test didn't cover. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_document_is_valid_openapi() reads the file from the package, so a broken /webapp/ static route or /openapi.json redirect, or a wrong Content-Type, went unnoticed. The new test fetches /openapi.json through build_handlers(), follows the redirect, and validates the body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
biolink/information-resource-registry#140 added infores:nodenorm for NodeNorm ES and renamed infores:sri-node-normalizer to NodeNorm Redis, so the two services no longer share an infores in SmartAPI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shuchenliu
added a commit
that referenced
this pull request
Nov 2, 2026
…avior (#58) * Rewrite the OpenAPI document to describe the Elasticsearch service The document was copied from NodeNorm Redis and never pruned, so it advertised TRAPI 1.5 (info.x-trapi), carried 145 schemas no path referenced, named RENCI's developer as the contact and sent readers to /get_curie_prefixes, which this service has never served. It also failed openapi-spec-validator: the /get_allowed_conflations response had no description, and FilterKgraphTopNParameters.max_edges declared maximum 0 (NCATSTranslator/NodeNormalization#409). Rewritten from scratch against build_handlers(): the six routes this service registers, nothing else. Responses that were `schema: {}` now have schemas (NormalizedNodes, SetIDResponse), the FastAPI 422 responses are replaced by the 400 the Tornado handlers raise, and the examples are taken from the live CI instance. The servers block lists the ci and test deployments at ITRB instead of RENCI. Contact is Will Liu and the team is DOGSURF (#35); infores and termsOfService are unchanged for now. info.version is bumped to 1.1.0 because /status reports it and the response shapes change in the next commit. handlers/curie_prefix.py was an unregistered copy of the semantic-types handler (its class is even named SemanticTypeHandler), so it goes too. Refs #35, #36 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Make two endpoints answer the way the OpenAPI document says GET /get_allowed_conflations finished a bare list, and Tornado's write() refuses a top-level list ("Lists not accepted for security reasons"), so it returned HTTP 500 on every deployment. It now returns {"conflations": [...]}, which is also what NodeNorm Redis returns. GET /get_semantic_types lower-cased every class ("biolink:namedthing"); NodeNorm Redis returns the Biolink class URI as is ("biolink:NamedThing"). /openapi.json now redirects to /webapp/openapi.json so the FastAPI default address used by NodeNorm Redis, SmartAPI and Babel Validation works here too; it is excluded from OpenTelemetry like the other static paths. The POST set-ID test posted a single object where the handler expects a list of sets, and the normalized-nodes docstring showed a "curie" key where the handler reads "curies"; both corrected. POST /get_setid still answers with an object keyed "0", "1", ... (the same Tornado limitation); returning a list as NodeNorm Redis does is a breaking change, so it is left to its own pull request. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test that the OpenAPI document matches the handlers The document is hand-written and served as a static file, so these tests are what stops it drifting: the spec validates; its paths are exactly the routes build_handlers() registers; each path documents the GET/POST methods its handler defines; each GET documents the query parameters its handler reads (found by scanning the handler source for get_argument calls); and the SetIDResponse schema lists the dataclass's fields. Each was checked to fail when the spec is mutated. Also a regression test for /get_allowed_conflations, which returned HTTP 500 until the previous commit: it mounts just that handler and validates the body against the documented ConflationList schema. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Document where the OpenAPI document lives and how it is kept in sync Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * Unit-test the semantic-type casing fix It ran only against the su10 Elasticsearch host before. This mounts the handler alone with a fake Elasticsearch client and validates the body against the documented schema. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Match /openapi.json and /favicon.ico literally The dot in each redirect pattern was unescaped, so /openapiXjson and /faviconXico redirected too. The OpenTelemetry exclusions already escape it. A test now checks the /openapi.json redirect and that a near-miss path is a 404. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Check POST bodies and helper-read parameters against the OpenAPI document The query-parameter check scanned only get() for get_argument calls, so a parameter read in a helper method would drift unnoticed; it now scans the whole handler class. A new check compares the fields each post() reads with .get("...") against the properties of the documented request body (CurieList, and the SetIDQuery items of the /get_setid array). Both were confirmed to fail when a field is removed from the document or a parameter is renamed in a helper. The checks still only see literal names; the README now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Return the set-ID error to the client instead of a 500 generate_setid() returned the SetIDResponse dataclass itself on the invalid-conflation and no-normalized-CURIEs paths. Tornado can only write dicts, so GET /get_setid?conflation=Bogus answered 500 and the documented `error` field never reached anyone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reject a POST /get_setid body that isn't an array of sets The body has to be a JSON array of {curies, conflations} objects. A single object (the shape the old document described) passed the length check and then failed with an AttributeError, and invalid JSON failed in json.loads; both were 500s. They are now 400s that say what shape the body must have. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Report status=error from /status when Elasticsearch is down The index mapping (for the Babel version) was read before the try block, so an unreachable cluster raised and /status answered 500 instead of the documented {"status": "error"}. The read now happens inside the try; babel_version and babel_version_url are null when the mapping couldn't be read, and the document says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Match API routes exactly The patterns were written r"/get_setid?", r"/status?" and so on. In a Tornado route that ? makes the last character optional, so /get_seti and /statu reached the handlers though the OpenAPI document lists only the full paths. test_openapi.py hid this by stripping the ? before comparing routes with the document; it now compares them as written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Scan the whole handler for POST body fields The request-body check read only post()'s source, though the README says fields are found by scanning the handler, and the query-parameter check already scans the whole class. A body field read in a helper method was either missed or reported as undocumented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Document HEAD /get_allowed_conflations and check every method The methods check compared only GET and POST, so the HEAD handler on /get_allowed_conflations, which the document didn't list, went unnoticed. It now compares every method Tornado routes except OPTIONS (answered by the base handler for CORS), and the document lists HEAD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Declare jsonschema as a test dependency tests/test_openapi.py imports it directly; it was only installed because openapi-spec-validator happens to depend on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Reject /get_normalized_nodes flags that aren't booleans parse_boolean() treated every string except "false" as true, so conflate=0 or conflate=no turned conflation on. The flags now accept the strings FastAPI/Pydantic accepted in NodeNorm Redis (true/false, 1/0, yes/no, on/off, t/f, y/n, in any case) and answer 400 for anything else, including an empty value. POST bodies go through the same check, so {"conflate": "false"} is no longer truthy. The document lists the accepted values. This is a behavior change: a caller sending an unrecognized value now gets a 400 where it used to get conflation silently switched on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test the empty-set early return in generate_setid() Covers the second path #47 describes: a set whose CURIEs normalize to nothing. get_normalized_nodes() is patched out, so it needs no host. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Explain why the route patterns have no trailing ? Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Use Will Liu's Scripps address as the API contact Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * List the production deployment in the OpenAPI servers https://nodenorm-es.transltr.io/ is now live. It goes first, since Swagger UI and generated clients default to the first server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Say what the semantic-types check in the API description is for Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Answer 400, not 500, to a POST /get_setid body that isn't UTF-8 json.loads() raises UnicodeDecodeError rather than JSONDecodeError for bytes that aren't valid UTF-8, so such a body escaped the check and became a 500, though the document promises a 400 for a malformed body. The decoding moves to a load_json_body() helper on the base handler so POST /get_normalized_nodes can use it too. Raised by Copilot on #42. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Answer 400, not 500, to a malformed POST /get_normalized_nodes body The handler called json.loads() with no error handling and then .get() on the result, so a body that wasn't JSON, wasn't UTF-8, or was an array instead of an object all became 500s. It now uses load_json_body() and checks for an object, and the document lists these under the 400 response. Same cause as the UTF-8 case Copilot raised for POST /get_setid on #42. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Validate the OpenAPI document as the server serves it test_document_is_valid_openapi() reads the file from the package, so a broken /webapp/ static route or /openapi.json redirect, or a wrong Content-Type, went unnoticed. The new test fetches /openapi.json through build_handlers(), follows the redirect, and validates the body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Identify the service as infores:nodenorm biolink/information-resource-registry#140 added infores:nodenorm for NodeNorm ES and renamed infores:sri-node-normalizer to NodeNorm Redis, so the two services no longer share an infores in SmartAPI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Change type field to accept null in openapi.json Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Gaurav Vaidya <gaurav@renci.org> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: gaurav <gaurav@ggvaidya.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Member
|
consolidated changes and merged with #58 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


src/nodenorm/webapp/openapi.jsonwas copied from NodeNorm Redis and never pruned, so it advertised TRAPI 1.5, carried 145 schemas that no path referenced, named RENCI's developer as the contact, pointed readers at/get_curie_prefixes(a 404 here) and failedopenapi-spec-validator. This PR rewrites it from scratch against the six routesbuild_handlers()registers, and fixes the endpoints that didn't do what the document says:GET /get_allowed_conflationsreturned HTTP 500 on every deployment,/get_semantic_typeslower-cased every Biolink class,/get_setidanswered 500 instead of itserrorfield,/statusanswered 500 rather thanstatus: errorwhen Elasticsearch was down,/get_normalized_nodesreadconflate=0as true, and a POST body that wasn't JSON answered 500 rather than 400. Closes #35. Closes #36. Closes #47.A test module now holds the document to the code, and
/openapi.jsonredirects to/webapp/openapi.jsonso the address NodeNorm Redis, SmartAPI and Babel Validation expect works here, which unblocks #34. Returning a list fromPOST /get_setid, as NodeNorm Redis does, is a breaking change left to #48, which builds on this one.Calls worth overruling
/get_allowed_conflationsreturns{"conflations": [...]}and/get_semantic_typesreturnsbiolink:NamedThingrather thanbiolink:namedthing, both to match NodeNorm Redis, which clients were written against./get_normalized_nodesaccepts the strings Pydantic accepted in NodeNorm Redis (true/false,1/0,yes/no,on/off,t/f,y/n, any case) in the query and the POST body, and answers 400 for anything else, including an empty value. Before, anything butfalsemeant true.POST /get_setidis documented as it answers today, an object keyed by input index ("0","1", …); Return POST /get_setid results as a JSON list, as NodeNorm Redis does #48 changes both the code and the document./statusreportsbabel_version: nullwhen the cluster can't be reached, rather than omitting the field.serversis a static list of the production,ciandtestdeployments at ITRB plus localhost (production first, as clients default to the first), not generated from environment variables as in NodeNorm Redis. Localhost stays asdevelopmentso a local Swagger UI can reach itself; Don't list localhost as the development server in the registered OpenAPI document #54 asks whether the registered document should keep it./versionis documented rather than removed (Remove TRAPI-specific content and references to missing endpoints from the OpenAPI document #36 offered either). It reports the deployed commit, which/statusdoesn't.422/HTTPValidationErrorthe old document copied.infores:nodenorm, added for this service by Add infores:nodenorm for NodeNorm ElasticSearch and rename the Redis entry biolink/information-resource-registry#140, which renamedinfores:sri-node-normalizerto NodeNorm Redis. The RENCI terms of service are unchanged for now (see below).What's here
The document shrinks from about 3,000 lines to about 600: six paths, eight schemas, one shared example taken from the live CI instance.
info.versionis bumped to 1.1.0 because/statusreports it and response shapes changed.handlers/curie_prefix.py, an unregistered copy of the semantic-types handler, is deleted. Both POST handlers parse their bodies with a sharedload_json_body(), so a body that isn't JSON, or isn't UTF-8, gets a 400. Route patterns are matched exactly; a comment inbuild_handlers()says why.tests/test_openapi.pyvalidates the document, both the file and the copy served at/openapi.json, and checks its paths, methods (HEAD included), query parameters, POST body fields andSetIDResponseschema against the handlers. It also mounts each fixed handler with a fake or unreachable Elasticsearch client and validates the answers against the documented schemas, so none of it needs thesu10host. The README's "OpenAPI document" section says how the document is kept in sync.What it deliberately does not do
/get_normalized_nodes,/versionor/status-when-up responses against their schemas without thesu10host: Check /get_normalized_nodes, /version and /status responses against the OpenAPI schemas without an Elasticsearch host #51.docker/patches/health.pyis a stale copy of the health handler; deleting it is Delete docker/patches/health.py, an unused stale copy of the health handler #45. Running the host-free tests in GitHub Actions is Run the tests that need no Elasticsearch host in GitHub Actions #44, and therequires-pythonrange that stopsuv runresolving the project is Raise requires-python to >=3.10 souv runcan resolve the project #43.Verification
On 3d000cc,
openapi-spec-validatorpasses, and the whole suite passes except the four integration tests that need thesu10host (test_node_normalization_get/_post, andtest_get_endpoint/test_post_endpointfor set IDs).After merging
Nothing blocks merging. Registering at SmartAPI (#34) waits until this is deployed to production: SmartAPI's uptime check tests only the first server, whose
/get_allowed_conflations500s until then. Deferred:info.descriptionlinks to in NodeNorm Redis'sdocumentation/API.md, in case NodeNorm Redis changes.🤖 Generated with Claude Code