go to post Theo Stolker · Feb 20 Hi @Evgeny Shvarov , Currently I am a busy with a couple of customer projects, but when I find the time I will publish it as an Open Exchange / IPM project Thanks, Theo
go to post Theo Stolker · Feb 1 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:
go to post Theo Stolker · Jan 24 @Evgeny Shvarov , one way to expose your local FHIR Endpoint would be through https://ngrok.com/use-cases/ingress-for-dev-test-environments Let me know if you have questions, Theo.
go to post Theo Stolker · Nov 28, 2023 The class ChangeLog.DB.PersistentWithChangeLog has just been changed. We had an issue with objects being part of the new data json, in which case %ToJSON() would fail. The code is now more robust.
go to post Theo Stolker · Sep 28, 2023 I found the issue, it has to do with the fact that the default lineTerminator for a stream on windows is CRLF, even inside docker. After applying https://github.com/lscalese/openapi-common-lib/pull/1 the API works like a charm. See https://github.com/lscalese/openapi-suite/issues/8
go to post Theo Stolker · Sep 27, 2023 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!
go to post Theo Stolker · Aug 24, 2023 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 = ""+-----------------------------------------------------
go to post Theo Stolker · Aug 23, 2023 A couple of clarifications: Replace "MMLOGGINGPKG.API.v1.spec" with your API spec You will have to tweak the schema as passed to GetValidator() to match what you want to validate 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. 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) }) }
go to post Theo Stolker · Aug 23, 2023 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 } }
go to post Theo Stolker · Aug 23, 2023 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!
go to post Theo Stolker · Jun 12, 2023 It would be helpful to also translate the code, because the non-English example code is still hard(er) to read and understand.
go to post Theo Stolker · May 25, 2023 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?
go to post Theo Stolker · Dec 27, 2022 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 }
go to post Theo Stolker · Dec 22, 2022 Yes, although the Python code does deal with an actual collection object :)
go to post Theo Stolker · Dec 22, 2022 /// 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
go to post Theo Stolker · Jul 8, 2022 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!