Thanks @Tani Frankel! I suspect the Support guidance is for when it is used in combination with HealthShare ODS production instances. When you run a local IRIS FHIR Repository as a developer, I believe there is no harm in using this. So the trick I was looking for is:

set ^HS.FHIRServer("dev") = 1

After refreshing the fhirconfig page, the new tile pops up:

Hi @Lorenzo Scalese,

I am applying openapi suite on the APIs published on https://nuts-node.readthedocs.io/en/stable/pages/integrating/api.html, and the result is disappointing, as no operations and/or messages have been generated. For the 7 openAPI specifications, the generated package is identical and quite empty. So to me this is not helpful.

Although a minor point, even the servers-property from the openapi specification  (url: http://localhost:1323) is being replaced with the location of the yaml file. Why?

I would like to discuss what we can do to make this better!

Hi André-Claud,

Taking the learning from @Eduard Lebedyuk, and just replacing ^MyGlobalName with %MyGlobalName would have worked:

do ##class(MMLOGGINGPKG.Util.Singleton).RunMe()
+----------------- general information ---------------
|      oref value: 55
|      class name: %ZEN.proxyObject
| reference count: 1
+----------------- attribute values ------------------
|           %changed = 1
|    %data("MyProp") = 22
|             %index = ""
+-----------------------------------------------------
Stored : 55@%ZEN.proxyObject

Got : 55@%ZEN.proxyObject
+----------------- general information ---------------
|      oref value: 55
|      class name: %ZEN.proxyObject
| reference count: 3
+----------------- attribute values ------------------
|           %changed = 1
|    %data("MyProp") = 22
|             %index = ""
+-----------------------------------------------------

A couple of clarifications:

  1. Replace "MMLOGGINGPKG.API.v1.spec" with your API spec
  2. You will have to tweak the schema as passed to GetValidator() to match what you want to validate
  3. The trick with $$$SchemaValidator is a way to create and initialize a singleton instance of the validator. The downside of that obviously is when you change the spec you have to make sure to restart the process in which the singleton resides.
  4. AddError is a classmethod that looks like: /// AddError ClassMethod AddError(fouten As %DynamicArray, regelnummer As %Integer, path As %String, error As %String) {     do fouten.%Push({ "regelnummer": (regelnummer), "path": (path), "error": (error) }) }  

This is the code that was the result:

/// Perform JSON Schema validation based on the API specification

Class MMLOGGINGPKG.Validations.JsonSchemaValidation

{

/// Validate against the schema

ClassMethod JsonIsValid(logregel As %DynamicObject, regelnummer As %String = "", errors As %DynamicArray, classname As %String) As %Boolean

{

    #define SchemaValidator %JSchemaValidator

    if '$Data($$$SchemaValidator) || '$IsObject($$$SchemaValidator)

    {

        set specification = {}.%FromJSON(##class(%Dictionary.XDataDefinition).%OpenId("MMLOGGINGPKG.API.v1.spec||OpenAPI").Data)

        // Prevent enum validations, these are too verbose

        do specification.definitions.Event.properties.type.%Remove("enum")

        do specification.definitions.Request.properties.method.%Remove("enum")

        set $$$SchemaValidator = ..GetValidator({

                "$ref": "#/definitions/Logregel",

                "definitions": (specification.definitions)

                }.%ToJSON())

    }

    return ..PythonJsonIsValid(logregel.%ToJSON(), $$$SchemaValidator, regelnummer, errors, classname)

}

/// Validate JSON using Python implementation of jsonschema

ClassMethod GetValidator(schema As %String) As %ObjectHandle [ Language = python ]

{

    import json

    from jsonschema import Draft4Validator

    jschema = json.loads(schema)

    return Draft4Validator(schema=jschema)

}

/// Validate JSON using Python implementation of jsonschema

ClassMethod PythonJsonIsValid(object As %String, validator As %ObjectHandle, regelnummer As %String, errors As %DynamicArray, classname As %String) As %Boolean [ Language = python ]

{

    import json

    import iris

    from jsonschema import Draft4Validator

    jobject = json.loads(object)

    valid = 1

    for error in validator.iter_errors(instance=jobject):

        try:

            valid = 0

            #; print(error.json_path) #; e.g. '$' or $.error.status

            path = error.json_path.replace("$.", "").replace("$", "")

            pattern = "Additional properties are not allowed ('"

            if path.count(".") == 0 and error.message.startswith(pattern):

                try:

                    object = error.path.pop() + "."

                except:

                    object = ""

                    pass

                x = error.message.replace(pattern, "")

                x = x.split("' w")[0]

                for attribute in x.split("', '"):

                    iris.cls(classname).AddError(errors, regelnummer, object + attribute, "Additional properties are not allowed")

            else:

                iris.cls(classname).AddError(errors, regelnummer, path, error.message)

            pass

        except Exception as xxend:

            print(xxend)

            pass

   

    return valid

}

}

Hi Yuri,

Great post! I had the challenge to validate incoming json for a REST API for which I had created a decent swagger 2.0 spec, which follows the Draft4 specification of jsonschema. I implemented a validator that:

  • Fetches the Swagger specification from the spec class
  • Uses https://github.com/python-jsonschema/jsonschema
  • In embedded Python code
    • Creates a specific validator for the Draft4 specification
    • Builds a nice JSON array with the errors found

One thing to specifically note is the need to add  "additionalProperties": false if you want to check against unexpected properties.

I'll paste the code in the next comment. Let me know if you have feedback or questions!

I watched the video as I was curious what was behind the bold title. So what is this "true interoperability"?

What I heard is that if institutions agree on the use of the same FHIR profile, these institutions will achieve a higher degree of interoperability as compared to just the syntactic operability achieved normally between HL7v2 and FHIR.

I do agree that is true! So institutions using the same FHIR profile(s) have reached a level of seamless / instant interoperability.

I guess at that point I am wondering: How can I put it to work? I found this video: Working with FHIR Profiles in InterSystems IRIS for Health. Are there any other relevant resources?

Thanks, Julius, that is really helpful!!

I have implemented the part of the method that I needed as follows:

/// Move FHIR resourceproperties in the followin order:
/// - resourceType
/// - id
/// - meta
/// - extension
ClassMethod FHIROrderResourceProperties(resource As %DynamicObject) As %DynamicObject
{
    #dim order as %DynamicArray = [ "resourceType", "id", "meta", "extension" ]
    #dim newObject as %DynamicObject = {}

    for index = 0:1:order.%Size() - 1
    {
        set element = order.%Get(index)
        set done(element) = 1

        if $EXTRACT(resource.%GetTypeOf(element), 1, 2) '= "un"
        {
            do newObject.%Set(element, resource.%Get(element)) 
        }
    }
    
    set iterator = resource.%GetIterator()

    while iterator.%GetNext(.element, .value)
    {
        if '$DATA(done(element))
        {
            do newObject.%Set(element, value)
        }
    }

    return newObject
}

/// Python reorder FHIR properties

ClassMethod PyFHIRResourceReOrder(resource As %String) As %String [ Language = python ]

{

    import json

    from collections import OrderedDict

    result = json.loads(resource, object_pairs_hook=OrderedDict)

    result.move_to_end("extension", last = False)

    result.move_to_end("meta", last = False)

    result.move_to_end("id", last = False)

    result.move_to_end("resourceType", last = False)

    return json.dumps(result)

}

This Python code is what I ended up with. It re-orders the properties "resourceType", "id", "meta" and "extension" to be at the start

Hi @Lorenzo,

Thanks for the great tool! I tried generating a Fitbit client based on https://dev.fitbit.com/build/reference/web-api/explore/fitbit-web-api-sw..., but it failed, because parameter names have "-" characters, and these cannot be part of a Property name. Therefore I extended the name() Class method  to also have the "-":

ClassMethod name(name As %String) As %String [ CodeMode = expression ]
{
$Translate(name, "$_-","")
}

The proxy generation still fails, and given that I don't use that right now, I have disabled that. With these changes everything works great!