changeset 1013:ab270400aae1

python: overriding core API
author Alain Mazy <am@osimis.io>
date Tue, 09 Jan 2024 11:50:17 +0100
parents 34f30ddc0dec
children fcfd53aa7446
files .hgignore Sphinx/source/plugins/python.rst Sphinx/source/plugins/python/extending-rest-api-2.py
diffstat 3 files changed, 72 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Mon Jan 08 13:39:15 2024 +0100
+++ b/.hgignore	Tue Jan 09 11:50:17 2024 +0100
@@ -4,3 +4,4 @@
 .vscode/
 *~
 *.orig
+*.pyc
\ No newline at end of file
--- a/Sphinx/source/plugins/python.rst	Mon Jan 08 13:39:15 2024 +0100
+++ b/Sphinx/source/plugins/python.rst	Tue Jan 09 11:50:17 2024 +0100
@@ -281,6 +281,31 @@
   ok
 
 
+Overriding the core REST API
+............................
+
+You may also use a python plugin to replace an existing REST API route:
+
+.. literalinclude:: python/extending-rest-api-2.py
+                    :language: python
+
+
+
+When calling the REST API from a python plugin, you may use e.g. 
+``RestApiPost`` to call the native Orthanc REST API and must
+call ``RestApiPostAfterPlugin`` to call the REST API from plugins.
+
+
+Note however, that, as of Orthanc 1.12.2, the Orthanc plugin SDK
+does not support multiple plugins implementing the same route.
+Orthanc will actually accept e.g a Python plugin that overrides
+a DICOMWeb route but it is impossible to tell which route
+will be called in the end since this depends on the registration 
+order of the plugins that is not deterministic.
+
+
+
+
 .. _python-changes:
   
 Listening to changes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Sphinx/source/plugins/python/extending-rest-api-2.py	Tue Jan 09 11:50:17 2024 +0100
@@ -0,0 +1,46 @@
+import orthanc
+import pprint
+import json
+
+# override the /instances POST route
+def OnInstances(output, uri, **request):
+    
+    # for POST, replace the core API route by your own implementation
+    if request['method'] == 'POST':
+        orthanc.LogWarning('I have received an instance')
+        # implement your own logic here
+        output.AnswerBuffer(json.dumps({"MyAnswer": "Instance Ignored"}), "application/json")
+    else:
+        # for GET, simply forward the call to the core API.
+        # Note that you should not use RestApiGetAfterPlugins here since
+        # this would call the /instances route from this python plugin
+        # and end up in an infinite loop.
+        instances = orthanc.RestApiGet(uri)
+        output.AnswerBuffer(instances, "application/json")
+
+# reimplement a DICOMWeb /studies/../metadata route
+def OnDicomWebStudiesMetadata(output, uri, **request):
+    
+    orthanc.LogWarning("My DICOMWEB /studies/../metadata")
+
+    # since we are calling a route from a plugin, we must use RestApiGetAfterPlugins
+    metadata = json.loads(orthanc.RestApiGetAfterPlugins(uri.replace('/my-dicom-web/', '/dicom-web/')))
+    
+    # transform the metadata (remove all tags from group 0009)
+    for m in metadata:
+        tags_to_remove = [k for k in m if k.startswith('0009')]
+        for k in tags_to_remove:
+            del m[k]
+
+    output.AnswerBuffer(json.dumps(metadata), "application/json")
+
+
+# override the /instances route from the core API
+orthanc.RegisterRestCallback('/instances', OnInstances)
+
+# The code below should be avoided since you actually don't know which route will finally be called:
+# the one from the DICOMWeb plugin or the one from this python plugin
+# orthanc.RegisterRestCallback('/dicom-web/studies/(.*)/metadata', OnDicomWebStudiesMetadata)
+
+# Therefore, you should use another base route to differentiate it from the DICOMWeb plugin route
+orthanc.RegisterRestCallback('/my-dicom-web/studies/(.*)/metadata', OnDicomWebStudiesMetadata)