Isn’t it amazing when you can answer your own question?
I’ve figured it out. To send a concept in JSON format you can use the following:
{"conceptClass":"8d4918b0-c2cc-11de-8d13-0010c6dffd0f","names":[{"conceptNameType":"FULLY_SPECIFIED","locale":"en","name":"Brown-Kelly-Paterson syndrome"}],"datatype":"8d4a4c94-c2cc-11de-8d13-0010c6dffd0f"}
Here is some sample code i’ve written:
package anu.jcmsr.mml.human
import grails.converters.JSON
import grails.plugins.rest.client.RestBuilder
import java.nio.charset.Charset
import org.apache.log4j.Logger
import org.codehaus.groovy.grails.web.json.JSONArray
import org.codehaus.groovy.grails.web.json.JSONObject
import org.springframework.http.HttpStatus
import org.springframework.http.converter.StringHttpMessageConverter
/**
* Service class for interacting with openmrs database
* @author Philip Wu
*
*/
//@Transactional
class OpenMrsService {
Logger logger = Logger.getLogger(OpenMrsService.class)
String conceptUrl = "http://localhost:8989/openmrs/ws/rest/v1/concept"
String conceptReferenceTermUrl = "http://localhost:8989/openmrs/ws/rest/v1/conceptreferenceterm"
String username = "Admin"
String password = "Admin123"
/**
* Following rest api reference
* https://wiki.openmrs.org/display/docs/REST+Web+Service+Resources+in+OpenMRS+1.9#RESTWebServiceResourcesinOpenMRS1.9-Concept
*
*/
def importSnomedCtConcepts() {
System.out.println("Start importSnomedCtConcepts")
// File columns (of interest)
final int INDEX_ID = 0
final int INDEX_ACTIVE = 2
final int INDEX_CONCEPT_ID = 4
final int INDEX_TYPE_ID = 6
final int INDEX_TERM = 7
File file = new File ("E:/snomedCT/NEHTA_2068_2015_SNOMEDCT-AU_ReleaseFileBundle_v20150531/SnomedCT_Release_AU1000036_20150531/RF2Release/Full/Terminology/sct2_Description_Full-en-AU_AU1000036_20150531.txt")
// Parse each line
file.eachLine { String line, Integer i ->
String[] lineParts = line.split("\t", -1)
Boolean active = (lineParts[INDEX_ACTIVE] == '1') ? Boolean.TRUE : Boolean.FALSE
// Only import if the concept is active
if (active) {
//System.out.println("line="+line)
String id = lineParts[INDEX_ID]
String conceptId = lineParts[INDEX_CONCEPT_ID]
String typeId = lineParts[INDEX_TYPE_ID]
String term = lineParts[INDEX_TERM]
/** Reference term */
// Check that the reference term doesn't already exist
String conceptRefTermUuid = conceptReferenceTermExists(conceptId)
//System.out.println("conceptRefTermUuid="+conceptRefTermUuid)
// If no existing record could be found, create a new one
if (conceptRefTermUuid == null) {
conceptRefTermUuid = saveConceptReferenceTerm(conceptId, term)
} else {
//System.out.println("Existing conceptRefTerm uuid="+conceptRefTermUuid)
}
try {
/** Concept */
// Check that the concept doesn't already exist
String conceptUuid = conceptExists(term)
// If it doesn't exist, create it
if (conceptUuid == null) {
conceptUuid = saveConcept(term)
//System.out.println("Saved concept uuid="+conceptUuid)
}
/** Concept mapping */
// Map the concept to snomed reference term
// Check that the mapping doesn't already exist
String conceptMappingUuid = conceptMappingExists(conceptUuid)
if (conceptMappingUuid == null) { // create a new mapping
conceptMappingUuid = saveConceptMapping(conceptUuid, conceptRefTermUuid)
}
} catch (Exception ex) {
// Workaround: Handle concepts with special character encoding such as, Déjerine-Roussy syndrome
if (ex.message?.contains("DuplicateConceptNameException")) {
// ignore
} else {
// rethrow
throw ex
}
}
}
}
System.out.println("End importSnomedCtConcepts")
}
/**
* Construct json object for concept reference term
* @param code
* @param conceptSourceUuid
* @return
*/
private JSONObject jsonConceptReferenceTerm(String code, String term, String conceptSourceUuid) {
JSONObject jsonConceptReferenceTerm = new JSONObject()
jsonConceptReferenceTerm.put("code", code)
jsonConceptReferenceTerm.put("name", term)
jsonConceptReferenceTerm.put("conceptSource", conceptSourceUuid)
return jsonConceptReferenceTerm
}
/**
* Create the concept represented as a JSON object from the given term
* @param term
* @return
*/
private JSONObject jsonConcept(String term) {
// Construct the json object
JSONObject jsonConcept = new JSONObject()
// Name
JSONArray jsonNames = new JSONArray()
JSONObject jsonName = new JSONObject()
jsonName.put("name", term)
jsonName.put("locale", "en")
jsonName.put("conceptNameType", "FULLY_SPECIFIED")
jsonNames.add(jsonName)
jsonConcept.put("names", jsonNames)
// Datatype
jsonConcept.put("datatype", '8d4a4c94-c2cc-11de-8d13-0010c6dffd0f')
// Concept class
jsonConcept.put("conceptClass", "8d4918b0-c2cc-11de-8d13-0010c6dffd0f")
return jsonConcept
}
/**
* Using the webservices, create the new concept reference term
* @param conceptId
* @param term
* @return
*/
private String saveConceptReferenceTerm(String conceptId, String term) {
// the UUID of the newly created reference term
String conceptRefTermUuid = null
// Create a new concept reference term
JSONObject jsonConceptReferenceTerm = jsonConceptReferenceTerm(conceptId, term, '2b3c054a-768a-102f-83f4-12313b04a615')
def resp = postJson(conceptReferenceTermUrl, jsonConceptReferenceTerm)
return resp.json.uuid
}
/**
* Using web services, save the concept name
* @param term
* @return
*/
private String saveConceptName(String term, String parentUuid) {
// Create the json object
JSONObject jsonConceptName = new JSONObject()
jsonConceptName.put("name", term)
jsonConceptName.put("locale", "en")
String uuid
String conceptNameUrl = conceptUrl + "/"+parentUuid+"/name"
def resp = postJson(conceptNameUrl, jsonConceptName)
return resp.json.uuid
}
/**
* Post JSON object using the given url
* @param url
* @param jsonObj
* @return
*/
private Object postJson(String url, JSONObject jsonObj) {
System.out.println("Posting: "+jsonObj.toString())
RestBuilder rest = new RestBuilder()
def resp = rest.post(url) {
auth 'Admin', 'Admin123'
contentType "application/json;charset=UTF-8"
json jsonObj as JSON
}
//System.out.println("savingConceptName status code="+resp.statusCode)
if (resp.statusCode == HttpStatus.CREATED) { // created
return resp
} else if (resp.statusCode == HttpStatus.INTERNAL_SERVER_ERROR) {
throw new Exception("OpenMRS internal error: "+resp.text)
} else if (resp.statusCode == HttpStatus.BAD_REQUEST) {
throw new Exception("OpenMRS bad request: "+resp.text)
}
}
/**
* Using web services, save the concept to the database
* @param term
* @return
*/
private String saveConcept(String term) {
String uuid = null
JSONObject jsonConcept = jsonConcept(term)
def resp = postJson(conceptUrl, jsonConcept)
return resp.json.uuid
}
/**
* Using web services, save the mapping between the concept and the reference term (mapping to snomed CT)
* @param conceptUuid
* @param conceptRefTermUuid
* @return
*/
private String saveConceptMapping(String conceptUuid, String conceptRefTermUuid) {
String conceptMappingUrl = conceptUrl + "/" + conceptUuid + "/mapping"
JSONObject jsonMapping = new JSONObject()
jsonMapping.put("conceptMapType", '35543629-7d8c-11e1-909d-c80aa9edcf4e') // SAME-AS
jsonMapping.put("conceptReferenceTerm", conceptRefTermUuid)
def resp = postJson(conceptMappingUrl, jsonMapping)
return resp.json.uuid
}
/**
* Check to see if the given concept code already exists as a reference term
* If it does, return the uuid
* @param code
* @return
*/
private String conceptReferenceTermExists(String conceptCode) {
String checkConceptRefTermUrl = conceptReferenceTermUrl + "?q="+conceptCode+"&v=default"
RestBuilder rest = new RestBuilder()
//rest.restTemplate.setMessageConverters([new StringHttpMessageConverter(Charset.forName("UTF-8"))])
def resp = rest.get(checkConceptRefTermUrl) {
auth username, password
}
//System.out.println("check conceptCode"+conceptCode+": "+resp.text)
for (Object conceptRefTerm: resp.json.results) {
if (conceptRefTerm.code?.equals(conceptCode)) {
System.out.println("found existing ref term: "+conceptRefTerm.uuid)
return conceptRefTerm.uuid
}
}
return null
}
/**
* Check to see if the given concept term already exists
* @param term
* @return
*/
private String conceptExists(String term) {
String checkConceptUrl = conceptUrl + "?v=custom:(uuid,name)&q="+term
RestBuilder rest = new RestBuilder()
//rest.restTemplate.setMessageConverters([new StringHttpMessageConverter(Charset.forName("UTF-8"))])
def resp = rest.get(checkConceptUrl) {
auth username, password
}
//System.out.println("conceptExists: "+resp.text)
for (Object concept: resp.json.results) {
if (concept.name?.name?.equals(term)) {
//System.out.println("found existing concept: "+concept.uuid)
return concept.uuid
}
}
return null
}
/**
* Check to see if the concept with the given UUID already has an existing mapping to snomed
* @return
*/
private String conceptMappingExists(String conceptUuid) {
String conceptMappingUrl = conceptUrl + "/" + conceptUuid + "/mapping?v=custom:(uuid,conceptMapType,conceptReferenceTerm)"
RestBuilder rest = new RestBuilder()
//rest.restTemplate.setMessageConverters([new StringHttpMessageConverter(Charset.forName("UTF-8"))])
def resp = rest.get(conceptMappingUrl) {
auth username, password
}
//System.out.println("conceptMappingExists: "+resp.text)
for (Object conceptMapping: resp.json.results) {
// If it is a SNOMED CT mapping, then return the UUID
String conceptSource = conceptMapping.conceptReferenceTerm?.conceptSource?.display
String conceptMapType = conceptMapping.conceptMapType?.name
if (conceptSource?.equals("SNOMED CT") && conceptMapType?.equals("SAME-AS")) {
return conceptMapping.uuid
}
}
return null
}
/**
* Testing locally
* @param args
*/
public static void main (String[] args) {
OpenMrsService service = new OpenMrsService()
service.importSnomedCtConcepts()
}
}