Completion – Last Update of GSoC @ OpenMRS

Everything is coming to a end in one day. So GSoC is about to finish as well. It was very successful journey with OpenMRS during GSoC time period. I’m very happy that I have selected OpenMRS as my GSoC organization. First I should thank my mentors Harsha and Sashrika for providing me the guidance to successfully complete the GSoC project. I should give my thank to Downey and Suranga who provide me valuable advices. Finally all of the community members of OpenMRS. Many members provided valuable suggestions to improve my project. Especially I should thank Pascal and Darius for their suggestions. So this is my last update from the GSoC @ OpenMRS. I’m going to summarize my GSoC work with this post.

Overview

My project idea is to generate swagger document of FHIR REST APIs available in OpenMRS FHIR Module. Swagger is becoming the standard of defining the RESTful web services. Swagger document of FHIR APIs provide comprehensive details of available FHIR  REST APIs of OpenMRS FHIR Module. The swagger document generated based on OpenAPI specification which is the international accepted specification to build swagger documentation of APIs. Swagger document defines a set of properties required to describe an API. These documents then used by the UI libraries to generate UI representation of swagger document, code generator tools to generate clients in various languages and etc. Additional utilities can also take advantage of the resulting files, such as testing tools. Following are the main parts of the OpenAPI specification. Figure 1 shows portion of swagger document generated as part of GSoC project. Figure 2 shows the integration of swagger UI which generate visual representation of swagger document. Figure 3 shows the expansion of a API operation.

swagger

Figure 1 : Overview of Swagger Document

screeen1Figure 2 : UI Representation of Swagger Document

example

Figure 3 : Expanded Location Resource GET Operation by ID

Project Resources

Project Documentation Link : https://wiki.openmrs.org/display/projects/FHIR+Swagger+Documentation

Project Discussion Link : https://talk.openmrs.org/t/fhir-swagger-document-generator-and-enhancements-next-steps/6040

Code Contributions: 

All Commitshttps://github.com/openmrs/openmrs-module-fhir/commits/master?author=rasanjanap

Swagger Document Generation

Code Pull Request : https://github.com/openmrs/openmrs-module-fhir/pull/120

Merged In : https://github.com/openmrs/openmrs-module-fhir/commit/808bc9ae52a24ac56ad2583a15fccad4f7669541

HAPI FHIR Library Upgrade

Code Pull Request : https://github.com/openmrs/openmrs-module-fhir/pull/122

Merged In :  https://github.com/openmrs/openmrs-module-fhir/commit/608b9f2d3f539da2c1a6c2c30108de5173854d51

Swagger UI Integration

Code Pull Request : https://github.com/openmrs/openmrs-module-fhir/pull/123

Merged In : https://github.com/openmrs/openmrs-module-fhir/commit/957efb9f3ef2ea8b3ab88424111cbd0c99016336

Adding Test Cases

Code Pull Request : https://github.com/openmrs/openmrs-module-fhir/pull/124

Merged In : https://github.com/openmrs/openmrs-module-fhir/commit/120b3eb72ea744316c7f1a8e03e74f18efe7aa6a

Summary

It has been nearly eight months which I have interact with OpenMRS. GSoC Open the door for me to contribute to Open Source World. So I decided to go with OpenMRS. I learn many new things during my GSoC period with OpenMRS. It was one of best experience of my life. I should thank for Google for organizing the GSoC and OpenMRS for giving me this valuable opportunity.

Advertisements

Documentation – 12th Week GSoC @ OpenMRS

This is the one last week prior to submit the evaluations and code. I still can’t believe how fast these three months have gone. This week my target was to complete the documentation. I have created the documentation page in OpenMRS wiki and added the content. You can view it here.  I’m posting complete documentation with this blog post as well.

Overview

Swagger Document of FHIR APIs gives comprehensive representation of available FHIR  REST APIs of OpenMRS FHIR Module. The swagger document is generated based on OpenAPI specification which is the international accepted specification to build swagger documentation of APIs. Swagger document defines a set of properties required to describe an API. These documents then used by the UI libraries to generate UI representation of swagger document, code generator tools to generate clients in various languages and etc. Additional utilities can also take advantage of the resulting files, such as testing tools. Following are the main parts of the OpenAPI specification.

  • General information about the API
    • General information about API such as who belongs it, licence, contact details
  • Available paths (/resources)
    • This contains all available resources of particular API. If we can take a example of user API, GET by /user/{id} is one resource which we can take details of a particular user and /user will be another resource where people can do POST requests to that endpoint to create users and search users with parameter.
  • Available operations on each path
    • Operations are the GET/DELETE/POST/PUT operations permitted in each of the resource. For example /user endpoint may have GET endpoint to search employees and POST to create users.
  • Input/Output for each operation
    • This section contains what are the inputs needed for the particular operation and output returned from the operation. POST request to /user resource will need user details as json while /user/{id} need input user id to get the details of a particular user.

openapi-specification-visual-documentation

Figure 1 : Representation of an API defined by OpenAPI

Swagger Documentation

The swagger documentation of FHIR API is available through http://{serverHost}:{serverPort}/openmrs/module/fhir/rest/swagger.json. In local deployment after installing FHIR module it’s available through http://localhost:8080/openmrs/module/fhir/rest/swagger.json. This provides details of all available resources exposed through FHIR API. Document provides supported http methods for each resource,  input object formats, output object formats and etc. Here is the full swagger document for the FHIR REST APIs. Figure 2 shows the overview of swagger document. It shows the information section and expanded Encounter resources that shows the available operations.

swagger

Figure 2 : Overview of Swagger Document

Figure 3 shows shorted format of json representation which include only a single resource which is encounter resource.

{

 “swagger”: “2.0”,

 “info”: {

   “version”: “1.0.0”,

   “title”: “OpenMRS FHIR REST Services”,

   “description”: “Auto-generated documentation for OpenMRS FHIR Rest services”,

   “termsOfService”: “https://www.mozilla.org/en-US/MPL/2.0/”,

   “contact”: {

     “name”: “OpenMRS FHIR Module Team”,

     “url”: “https://talk.openmrs.org/c/dev”,

     “email”: “community@openmrs.org”

   },

   “license”: {

     “name”: “Mozilla Public License, v. 2.0”,

     “url”: “http://openmrs.org/license/”

   }

 },

 “host”: “localhost:8080”,

 “basePath”: “/openmrs/ws/fhir”,

 “consumes”: [

   “application/xml”,

   “application/json”

 ],

 “produces”: [

   “application/json”,

   “application/xml”,

   “application/xml+fhir”,

   “application/json+fhir”

 ],

 “paths”: {

   “/Encounter”: {

     “post”: {

       “summary”: “Create Encounter resource from the content of the request”,

       “produces”: [

         “application/json”,

         “application/xml”,

         “application/xml+fhir”,

         “application/json+fhir”

       ],

       “parameters”: [

         {

           “name”: “body”,

           “in”: “body”,

           “description”: “Encounter resource object”,

           “required”: true,

           “schema”: {

             “$ref”: “#/definitions/Encounter”

           }

         }

       ],

       “responses”: {

         “200”: {

           “description”: “Returns success operation outcome”,

           “schema”: {

             “type”: “object”,

             “$ref”: “#/definitions/OperationOutcome”

           },

           “examples”: {

             “application/json”: “{\”resourceType\”:\”OperationOutcome\”,\”issue\”:[{\”severity\”:\”information\”,\”details\”:\”Details of operation\”}]}”

           }

         },

         “404”: {

           “description”: “When error occurred”,

           “schema”: {

             “type”: “object”,

             “$ref”: “#/definitions/GeneralError”

           },

           “examples”: {

             “application/json”: “{\”resourceType\”:\”OperationOutcome\”,\”issue\”:[{\”severity\”:\”error\”,\”details\”:\”Details of error\”}]}”

           }

         }

       }

     },

     “get”: {

       “summary”: “Returns Encounter matching results”,

       “produces”: [

         “application/json”,

         “application/xml”,

         “application/xml+fhir”,

         “application/json+fhir”

       ],

       “parameters”: [

         {

           “name”: “patient”,

           “in”: “query”,

           “description”: “”,

           “required”: false,

           “type”: “string”

         },

         {

           “name”: “part-of”,

           “in”: “query”,

           “description”: “”,

           “required”: false,

           “type”: “string”

         },

         {

           “name”: “_id”,

           “in”: “query”,

           “description”: “The ID of the resource”,

           “required”: false,

           “type”: “string”

         }

       ],

       “responses”: {

         “200”: {

           “description”: “Bundle of Encounter resources”,

           “schema”: {

             “type”: “array”,

             “$ref”: “#/definitions/Encounter”

           },

           “examples”: {

             “application/json”: “{\n  \”resourceType\”: \”Encounter\”,\n  \”status\”: \”finished\”,\n  \”class\”: \”inpatient\”,\n  \”subject\”: {\n    \”reference\”: \”Patient/dd738d54-1691-11df-97a5-7038c432aabf\”,\n    \”display\”: \”Daisylene Ekeno(Identifier:1865TU-8)\”\n  },\n  \”participant\”: [\n    {\n      \”individual\”: {\n        \”reference\”: \”Practitioner/bf218490-1691-11df-97a5-7038c432aabf\”,\n        \”display\”: \”Super User(Identifier:admin)\”\n      }\n    }\n  ],\n  \”period\”: {\n    \”start\”: \”2006-02-07T00:00:00\”,\n    \”end\”: \”2006-02-07T00:00:00\”\n  },\n  \”location\”: [\n    {\n      \”location\”: {\n        \”reference\”: \”Location/8d6c993e-c2cc-11de-8d13-0010c6dffd0f\”,\n        \”display\”: \”Inpatient Ward\”\n      },\n      \”period\”: {\n        \”start\”: \”2006-02-07T00:00:00\”,\n        \”end\”: \”2006-02-07T00:00:00\”\n      }\n    }\n  ]\n}”

           }

         },

         “404”: {

           “description”: “When error occurred”,

           “schema”: {

             “type”: “object”,

             “$ref”: “#/definitions/GeneralError”

           },

           “examples”: {

             “application/json”: “{\”resourceType\”:\”OperationOutcome\”,\”issue\”:[{\”severity\”:\”error\”,\”details\”:\”Details of error\”}]}”

           }

         }

       }

     }

   }

 },

 “definitions”: {

   “Condition”: {

     “type”: “object”

   },

   “Bundle”: {

     “type”: “object”

   },

   “DiagnosticReport”: {

     “type”: “object”

   },

   “Patient”: {

     “type”: “object”

   },

   “Practitioner”: {

     “type”: “object”

   },

   “AllergyIntolerance”: {

     “type”: “object”

   },

   “FamilyMemberHistory”: {

     “type”: “object”

   },

   “OperationOutcome”: {

     “type”: “object”

   },

   “Observation”: {

     “type”: “object”

   },

   “Encounter”: {

     “type”: “object”

   },

   “Person”: {

     “type”: “object”

   },

   “GeneralError”: {

     “type”: “object”

   },

   “Location”: {

     “type”: “object”

   }

 },

 “externalDocs”: {

   “description”: “Find more info here”,

   “url”: “https://wiki.openmrs.org/display/projects/OpenMRS+FHIR+Module”

 },

 “parameters”: {

   “formatParam”: {

     “name”: “_format”,

     “in”: “query”,

     “description”: “Format parameter can use to get response by setting _fromat param value  from xml by _format=xml and response from json by _format=json”,

     “required”: false,

     “type”: “string”

   }

 }

}

Figure 3 : Swagger Document JSON Representation

UI Representation

The FHIR module comes with a rich UI to represent the FHIR REST API swagger documentation which built using swagger UI library. User can navigate to Administration view of the OpenMRS UI and then click on Swagger Documentation link under the FHIR Module links as in Figure 4.

location

Figure 4 : FHIR Module Swagger Documentation Link

 

Figure 5 shows the Swagger Document UI representation. It listed operations of all available resources based on HTTP Method such as GET, PUT, POST, DELETE and HEAD. This is located at http://{serverHost}:{serverPort}/openmrs/module/fhir/apidocs.form#/default location. For local installations, user can view this through accessing http://localhost:8080/openmrs/module/fhir/apidocs.form#/default URL.

screeen1

  Figure 5 : UI Representation of Swagger Document

Figure 6 shows the expanded view of GET operation of Location resource. It shows query parameters supported the operation and description of each query parameter and the success response format. Likewise each operation contains comprehensive set of details which can be used as a full representation of a API. Figure 7 shows the expanded view of Location POST operation which indicate the properties of Location creation request.

locationres

Figure 6 : Expanded Location Resource GET Operation

locationpost

Figure 7 : Expanded Location Resource POST Operation

API Invocation

Swagger UI implementation support testing the API through the UI itself. By filling appropriate values in query parameter in GET operation or body parameter in POST operation, user can invoke an API. Figure 7 shows invocation result of  GET Patient by UUID.

example

Figure 7 : Invocation of Get Patient By UUID Operation

Summary

The swagger representation of an API is very powerful resource to get the full details of a API. Swagger document of FHIR APIs contains all required information required to represent the OpenMRS FHIR API. As discussed above, user can retrieve the swagger document json representation from the swagger document endpoint in http://{serverHost}:{serverPort}/openmrs/module/fhir/rest/swagger.json. Powerful swagger document UI representation allows users to go through all available resources and it’s details very easily and try out the available operations instantly. On other hand swagger document can used to generate clients in any language which can be directly used within applications. Swagger is becoming more and more popular among the community. On the other hand, having FHIR API represent through swagger enhance the understandability of the API for users.

Finalizing – 11th Week of GSoC @ OpenMRS

This week I have target on finishing the test cases for the swagger implementation and do a fully recap on the tasks that I have carried out. Since nearly two weeks to go, I have started to finalizing things and revisit on what I have left to do. Writing test cases was a remaining task that I have completed this week. I encounter several issues while writing the test. I have created omod test module and wrote a test. But the there is a class which initialize when request comes to the sever which set several properties of hapi fhir library. Since this class not getting initialize, it cause null pointer exceptions when I running the tests. I got below null pointer exception.

java.lang.NullPointerException
at org.openmrs.module.fhir.server.ConformanceProvider.getConformance(ConformanceProvider.java:31)
at org.openmrs.module.fhir.swagger.SwaggerSpecificationCreator.<init>(SwaggerSpecificationCreator.java:55)
at org.openmrs.module.fhir.omod.SwaggerDocumentGenerationTestCase.generateSwaggerDocumentation_shouldGenerateSwaggerDocumentation(SwaggerDocumentGenerationTestCase.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

But after digging through, I got a help from my mentor to the initialization on the test class itself. By doing that I was able to get rid of the null pointer exception. But then I encounter exception where it try to find spring service. After some digging I figured it out that without extending BaseModuleContextSensitiveTest, the spring services won’t be get initialize. I tried to do same in the omod test classes but it doesn’t allow to extend from that class. Then I further analyzed and removed the section that looks for the spring service and able to finish it.With this, implementation works are almost done. It was a great experience.

The review – 10th Week of GSoC @ OpenMRS

Time runs very fast. It’s hard to believe that GSoC is going to end in few weeks. This week my main targets was to do a complete review on the code and write test cases. I wanted to do a full review before I start final testing during this week. So plan was to identify the improvements that needed to perform on the code and the functionality improvements. First I went through the code base and check the code. Then I tested the swagger document generator and the swagger document output from the generator. Carefully went through the swagger document along with the Open API specification to check whether I need to do any further changes. After verification, I moved to swagger UI and tested it with some samples. I’m really happy that it works perfectly.

Later days, I checked on how I can write some test cases. But I found a blocker where, we need to initialize the conformance provider to get the FHIR conformance statement. At the moment when omod tests are running it doesn’t get initialize as a result I’m getting a null pointer exception. I asked suggestions in the talk forum to initialize it and I’m currently finding the workarounds for this. Hopefully I will be able to complete it soon.

 

 

 

 

 

Swagger UI Enhancements – 9th week of GSoC @ OpenMRS

This week my target was to wrap up the swagger UI integration and invoke FHIR Rest APIs from swagger console. Previous week I was able to integrate swagger UI library to OMOD. This week I have test the invocation of APIs through the swagger UI. It’s working perfectly. Below are the screenshot of invoking GET patient method.

patientresponse
Image 1 : Invocation of Patient GET Operation

With this integration, the swagger UI related works almost completed. Next week my focus is to go through the whole implementation and test it for the functionality along with writing test cases. Works with swagger was very good experience.

The Swagger UI – 8th Week of GSOC @ OpenMRS

This week I fully worked on integrating the swagger UI to the module. I have asked several questions on OpenMRS talk on the decision where we should integrate the swagger UI. Depend on the ideas of my mentor and other community members, we decided to integrate the swagger UI with the omod itself. I have went through the swagger UI library and how to add a web page for module to get the integration done. There are several challenges when I integrating the swagger UI. Here are sample screenshots which shows swagger resources of FHIR API through the module.

screeen1
Image 1 : FHIR API Resources
screeeen2
Image 2 : Expansion of FHIR Operation

Currently there are some issues with stylings and invoking APIs which I currently working on. The plan is to finish them within next week. It was very productive week as I able to complete the basic swaggger UI integration.

The Research and Performance Test – 7th Week of GSoC @ OpenMRS

This week I mainly work on researching and performance test the swagger API. There was a performance issue which reported by Judy who is a active developer of the community. So my mentor asked me to do a performance test on the swagger document API. I have done some search on tools on doing performance testing and found out that I can use Apache Jmeter to send http requests continuously.  I have setup a test plan to hit the swagger doc API endpoint with 50 concurrent threads. Below are the memory and thread usages graphs.

memory1
Memory
threads
Threads

The Judy reported that server got crashed with load, but I couldn’t reproduce similar thing as test run for several hours without any issue. I think memory may have become  issue in Judy’s setup.

Afterwards, I did a comprehensive research on where we should build the swagger UI. When I’m look at the Open Web App module, it’s based on OpenMRS 1.9.7 which is not latest. FHIR module uses beta version 2.0.0 release and going to upgrade to latest. If we also build a Open Web App, user will be needed to install two modules to get the swagger UI. Also I looked at the resources pointed by Pascal. It also not listed as a OpenMRS module list yet. Having code in a different repository will make it difficult for user to try out. I think best thing is to have all things self contained by integrating swagger UI to FHIR module itself for the moment and let users to try out. I think it will be one page implementation which can move to other module without a major changes.