diff OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp @ 4936:8422e4f99a18 more-tags

Handling RequestedTags in ExpandResource -> read parent main dicom tags if required. Not yet getting missing tags from file. Integration tests ok
author Alain Mazy <am@osimis.io>
date Fri, 11 Mar 2022 17:38:16 +0100
parents acd3f72e2a21
children 3f9b9865c8cc
line wrap: on
line diff
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Thu Mar 10 19:00:43 2022 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri Mar 11 17:38:16 2022 +0100
@@ -130,7 +130,8 @@
                                     const std::list<std::string>& resources,
                                     ResourceType level,
                                     bool expand,
-                                    DicomToJsonFormat format)
+                                    DicomToJsonFormat format,
+                                    const std::set<DicomTag>& requestedTags)
   {
     Json::Value answer = Json::arrayValue;
 
@@ -140,7 +141,7 @@
       if (expand)
       {
         Json::Value expanded;
-        if (context.ExpandResource(expanded, *resource, level, format))
+        if (context.ExpandResource(expanded, *resource, level, format, requestedTags))
         {
           answer.append(expanded);
         }
@@ -161,6 +162,7 @@
     if (call.IsDocumentation())
     {
       OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+      OrthancRestApi::DocumentRequestedTags(call);
 
       const std::string resources = GetResourceTypeText(resourceType, true /* plural */, false /* lower case */);
       call.GetDocumentation()
@@ -182,6 +184,9 @@
 
     std::list<std::string> result;
 
+    std::set<DicomTag> requestedTags;
+    OrthancRestApi::GetRequestedTags(requestedTags, call);
+
     if (call.HasArgument("limit") ||
         call.HasArgument("since"))
     {
@@ -209,7 +214,8 @@
     }
 
     AnswerListOfResources(call.GetOutput(), context, result, resourceType, call.HasArgument("expand"),
-                          OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human));
+                          OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human),
+                          requestedTags);
   }
 
 
@@ -220,6 +226,7 @@
     if (call.IsDocumentation())
     {
       OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+      OrthancRestApi::DocumentRequestedTags(call);
 
       const std::string resource = GetResourceTypeText(resourceType, false /* plural */, false /* lower case */);
       call.GetDocumentation()
@@ -227,12 +234,6 @@
         .SetSummary("Get information about some " + resource)
         .SetDescription("Get detailed information about the DICOM " + resource + " whose Orthanc identifier is provided in the URL")
         .SetUriArgument("id", "Orthanc identifier of the " + resource + " of interest")
-        .SetHttpGetArgument("requestedTags", RestApiCallDocumentation::Type_String,
-                            "If present, list the DICOM Tags you want to list in the response.  This argument is a semi-column separated list "
-                            "of DICOM Tags identifiers; e.g: 'requestedTags=0010,0010;PatientBirthDate'.  "
-                            "The tags requested tags are returned in the 'RequestedTags' field in the response.  "
-                            "Note that, if you are requesting tags that are not listed in the Main Dicom Tags stored in DB, building the response "
-                            "might be slow since Orthanc will need to access the DICOM files.  If not specified, Orthanc will return ", false)
         .AddAnswerType(MimeType_Json, "Information about the DICOM " + resource)
         .SetHttpGetSample(GetDocumentationSampleResource(resourceType), true);
       return;
@@ -240,22 +241,12 @@
 
     const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human);
 
-    std::set<DicomTag> responseTags;
-    if (call.HasArgument("requestedTags"))
-    {
-      try
-      {
-        FromDcmtkBridge::ParseListOfTags(responseTags, call.GetArgument("requestedTags", ""));
-      }
-      catch (OrthancException& ex)
-      {
-        throw OrthancException(ErrorCode_BadRequest, std::string("Invalid requestedTags argument: ") + ex.What() + " " + ex.GetDetails());
-      }
-    }
+    std::set<DicomTag> requestedTags;
+    OrthancRestApi::GetRequestedTags(requestedTags, call);
 
     Json::Value json;
     if (OrthancRestApi::GetContext(call).ExpandResource(
-          json, call.GetUriComponent("id", ""), resourceType, format)) // TODO, requestedTags))
+          json, call.GetUriComponent("id", ""), resourceType, format, requestedTags))
     {
       call.GetOutput().AnswerJson(json);
     }
@@ -2867,9 +2858,10 @@
       void Answer(RestApiOutput& output,
                   ServerContext& context,
                   ResourceType level,
-                  bool expand) const
+                  bool expand,
+                  const std::set<DicomTag>& requestedTags) const
       {
-        AnswerListOfResources(output, context, resources_, level, expand, format_);
+        AnswerListOfResources(output, context, resources_, level, expand, format_, requestedTags);
       }
     };
   }
@@ -2911,7 +2903,6 @@
                          "Note that, if you are requesting tags that are not listed in the Main Dicom Tags stored in DB, building the response "
                          "might be slow since Orthanc will need to access the DICOM files.  If not specified, Orthanc will return "
                          "all Main Dicom Tags to keep backward compatibility with Orthanc prior to 1.11.0.", false)
-
         .SetRequestField(KEY_QUERY, RestApiCallDocumentation::Type_JsonObject,
                          "Associative array containing the filter on the values of the DICOM tags", true)
         .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information "
@@ -2921,8 +2912,6 @@
 
     ServerContext& context = OrthancRestApi::GetContext(call);
 
-    // MORE_TAGS: TODO: handle RequestedTags
-
     Json::Value request;
     if (!call.ParseJsonRequest(request) ||
         request.type() != Json::objectValue)
@@ -2960,6 +2949,12 @@
       throw OrthancException(ErrorCode_BadRequest, 
                              "Field \"" + std::string(KEY_SINCE) + "\" should be an integer");
     }
+    else if (request.isMember(KEY_REQUESTED_TAGS) &&
+             request[KEY_REQUESTED_TAGS].type() != Json::arrayValue)
+    {
+      throw OrthancException(ErrorCode_BadRequest, 
+                             "Field \"" + std::string(KEY_REQUESTED_TAGS) + "\" should be an array");
+    }
     else
     {
       bool expand = false;
@@ -3000,6 +2995,13 @@
         since = static_cast<size_t>(tmp);
       }
 
+      std::set<DicomTag> requestedTags;
+
+      if (request.isMember(KEY_REQUESTED_TAGS))
+      {
+        FromDcmtkBridge::ParseListOfTags(requestedTags, request[KEY_REQUESTED_TAGS]);
+      }
+
       ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString());
 
       DatabaseLookup query;
@@ -3027,7 +3029,7 @@
 
       FindVisitor visitor(OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human));
       context.Apply(visitor, query, level, since, limit);
-      visitor.Answer(call.GetOutput(), context, level, expand);
+      visitor.Answer(call.GetOutput(), context, level, expand, requestedTags);
     }
   }
 
@@ -3039,6 +3041,7 @@
     if (call.IsDocumentation())
     {
       OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+      OrthancRestApi::DocumentRequestedTags(call);
 
       const std::string children = GetResourceTypeText(end, true /* plural */, false /* lower case */);
       const std::string resource = GetResourceTypeText(start, false /* plural */, false /* lower case */);
@@ -3055,6 +3058,9 @@
 
     ServerIndex& index = OrthancRestApi::GetIndex(call);
 
+    std::set<DicomTag> requestedTags;
+    OrthancRestApi::GetRequestedTags(requestedTags, call);
+
     std::list<std::string> a, b, c;
     a.push_back(call.GetUriComponent("id", ""));
 
@@ -3084,7 +3090,7 @@
            it = a.begin(); it != a.end(); ++it)
     {
       Json::Value resource;
-      if (OrthancRestApi::GetContext(call).ExpandResource(resource, *it, end, format))
+      if (OrthancRestApi::GetContext(call).ExpandResource(resource, *it, end, format, requestedTags))
       {
         result.append(resource);
       }
@@ -3162,6 +3168,7 @@
     if (call.IsDocumentation())
     {
       OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+      OrthancRestApi::DocumentRequestedTags(call);
 
       const std::string parent = GetResourceTypeText(end, false /* plural */, false /* lower case */);
       const std::string resource = GetResourceTypeText(start, false /* plural */, false /* lower case */);
@@ -3177,7 +3184,10 @@
     }
 
     ServerIndex& index = OrthancRestApi::GetIndex(call);
-    
+
+    std::set<DicomTag> requestedTags;
+    OrthancRestApi::GetRequestedTags(requestedTags, call);
+
     std::string current = call.GetUriComponent("id", "");
     ResourceType currentType = start;
     while (currentType > end)
@@ -3199,7 +3209,7 @@
     const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human);
 
     Json::Value resource;
-    if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format))
+    if (OrthancRestApi::GetContext(call).ExpandResource(resource, current, end, format, requestedTags))
     {
       call.GetOutput().AnswerJson(resource);
     }
@@ -3438,7 +3448,7 @@
   {
     static const char* const LEVEL = "Level";
     static const char* const METADATA = "Metadata";
-      
+
     if (call.IsDocumentation())
     {
       OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
@@ -3450,7 +3460,7 @@
                          "List of the Orthanc identifiers of the patients/studies/series/instances of interest.", true)
         .SetRequestField(LEVEL, RestApiCallDocumentation::Type_String,
                          "This optional argument specifies the level of interest (can be `Patient`, `Study`, `Series` or "
-                         "`Instance`). Orthanc will loop over the items inside `Resources`, and explorer upward or "
+                         "`Instance`). Orthanc will loop over the items inside `Resources`, and explore upward or "
                          "downward in the DICOM hierarchy in order to find the level of interest.", false)
         .SetRequestField(METADATA, RestApiCallDocumentation::Type_Boolean,
                          "If set to `true` (default value), the metadata associated with the resources will also be retrieved.", false)
@@ -3571,7 +3581,9 @@
                it = interest.begin(); it != interest.end(); ++it)
         {
           Json::Value item;
-          if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format))
+          std::set<DicomTag> emptyRequestedTags;  // not supported for bulk content
+
+          if (OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags))
           {
             if (metadata)
             {
@@ -3593,8 +3605,10 @@
         {
           ResourceType level;
           Json::Value item;
+          std::set<DicomTag> emptyRequestedTags;  // not supported for bulk content
+
           if (index.LookupResourceType(level, *it) &&
-              OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format))
+              OrthancRestApi::GetContext(call).ExpandResource(item, *it, level, format, emptyRequestedTags))
           {
             if (metadata)
             {