Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature request] Support URN id references #263

Closed
mikaello opened this issue May 22, 2022 · 2 comments
Closed

[Feature request] Support URN id references #263

mikaello opened this issue May 22, 2022 · 2 comments

Comments

@mikaello
Copy link

It seems that JSON Schemas with references built with URN is not supported, e.g. these schemas:

When trying to dereference these, the following error messages are produced respectively:

{
  stack: 'ResolverError: Error opening file "urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass" \n' +
    "ENOENT: no such file or directory, open 'urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass'\n" +
    '    at ReadFileContext.callback (/home/mikaelol/projects/temp/json-parse/node_modules/@apidevtools/json-schema-ref-parser/lib/resolvers/file.js:52:20)\n' +
    '    at FSReqCallback.readFileAfterOpen [as oncomplete] (node:fs:314:13)',
  code: 'ERESOLVER',
  message: 'Error opening file "urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass" \n' +
    "ENOENT: no such file or directory, open 'urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass'",
  source: 'urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass',
  path: null,
  toJSON: [Function: toJSON],
  ioErrorCode: 'ENOENT',
  name: 'ResolverError',
  footprint: 'null+urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass+ERESOLVER+Error opening file "urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass" \n' +
    "ENOENT: no such file or directory, open 'urn:jsonschema/:org:phenopackets:api:model:ontology:OntologyClass'",
  toString: [Function: toString]
}

and

{
  stack: 'ResolverError: Error opening file "urn:jsonschema/:iof:v3:Country" \n' +
    "ENOENT: no such file or directory, open 'urn:jsonschema/:iof:v3:Country'\n" +
    '    at ReadFileContext.callback (/home/mikaelol/projects/temp/json-parse/node_modules/@apidevtools/json-schema-ref-parser/lib/resolvers/file.js:52:20)\n' +
    '    at FSReqCallback.readFileAfterOpen [as oncomplete] (node:fs:314:13)',
  code: 'ERESOLVER',
  message: 'Error opening file "urn:jsonschema/:iof:v3:Country" \n' +
    "ENOENT: no such file or directory, open 'urn:jsonschema/:iof:v3:Country'",
  source: 'urn:jsonschema/:iof:v3:Country',
  path: null,
  toJSON: [Function: toJSON],
  ioErrorCode: 'ENOENT',
  name: 'ResolverError',
  footprint: 'null+urn:jsonschema/:iof:v3:Country+ERESOLVER+Error opening file "urn:jsonschema/:iof:v3:Country" \n' +
    "ENOENT: no such file or directory, open 'urn:jsonschema/:iof:v3:Country'",
  toString: [Function: toString]
}
@jonluca
Copy link
Collaborator

jonluca commented Mar 6, 2024

I'm not sure this is straightforward to support generically - I'd recommend writing your own custom resolver for the URN namespaces you want to support

@jonluca jonluca closed this as completed Mar 6, 2024
@mikaello
Copy link
Author

mikaello commented Mar 6, 2024

Thanks for getting back to me. In JVM world it is not that troublesome to support generically by leveraging the Jackson library, here is an example I have written in Kotlin (see parseReference function at the bottom):

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.databind.node.TextNode

private val typeMap = mutableMapOf<String, String>()

private fun parseReferences(jsonNode: JsonNode, path: String) {
    val ITEMS = "items"
    val ID = "id"
    val PROPERTIES = "properties"
    val ADDITIONAL_PROPERTIES = "additionalProperties"
    val REF = "\$ref"

    var currPath = path

    if (jsonNode.has(ID)) {
        typeMap.put(jsonNode.get(ID).asText(), currPath)
        val properties: JsonNode = jsonNode.get(PROPERTIES)
        val fields: Iterator<Map.Entry<String, JsonNode>> = properties.fields()
        currPath += "/$PROPERTIES"
        while (fields.hasNext()) {
            val entry = fields.next()
            parseReferences(entry.value, currPath + "/" + entry.key)
        }
    } else if (jsonNode.has(ITEMS)) {
        val item: JsonNode = jsonNode.get(ITEMS)
        parseReferences(item, "$currPath/$ITEMS")
    } else if (jsonNode.has(REF)) {
        val objectNode = jsonNode as ObjectNode
        objectNode.set(REF, TextNode(typeMap.get(jsonNode.get(REF).asText())))
    } else if (jsonNode.has(ADDITIONAL_PROPERTIES)) {
        val additionalProperties: JsonNode = jsonNode.get(ADDITIONAL_PROPERTIES)
        parseReferences(additionalProperties, "$currPath/$ADDITIONAL_PROPERTIES")
    }
}

/**
 * Remove URN from JSON, and replace with # type references
 */
fun parseReference(json: String): String {
    val jaxbObjectMapper = ObjectMapper()
    val root: JsonNode = jaxbObjectMapper.readTree(json)
    parseReferences(root, "#")
    return jaxbObjectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(root)
}

So that is why I thought this should be doable without to much trouble in TypeScript as well. URNs are valid IDs in JSON Schema, so I guess this affects others as well.

@mikaello mikaello changed the title [Feature reques] Support URN id references [Feature request] Support URN id references Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants