changeset 5829:963945d780d6 find-refactoring tip

tools/find ResponseContent
author Alain Mazy <am@orthanc.team>
date Mon, 07 Oct 2024 18:10:08 +0200
parents 7030fa489669
children
files NEWS OrthancServer/Sources/OrthancFindRequestHandler.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/OrthancWebDav.cpp OrthancServer/Sources/ResourceFinder.cpp OrthancServer/Sources/ResourceFinder.h OrthancServer/Sources/ServerEnumerations.cpp OrthancServer/Sources/ServerEnumerations.h
diffstat 8 files changed, 265 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Oct 07 15:19:26 2024 +0200
+++ b/NEWS	Mon Oct 07 18:10:08 2024 +0200
@@ -39,6 +39,8 @@
   - 'ParentPatient', 'ParentStudy', 'ParentSeries' to retrieve only descendants of an
     Orthanc resource.
   - 'QueryMetadata' to filter results based on metadata values.
+  - 'ResponseContent' to define what shall be included in the response for each returned
+    resource (e.g: Metadata, Children, ...)
 
 
 Maintenance
--- a/OrthancServer/Sources/OrthancFindRequestHandler.cpp	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/OrthancFindRequestHandler.cpp	Mon Oct 07 18:10:08 2024 +0200
@@ -631,7 +631,7 @@
        * EXPERIMENTAL VERSION
        **/
 
-      ResourceFinder finder(level, false /* don't expand */);
+      ResourceFinder finder(level, ResponseContentFlags_ID);
       finder.SetDatabaseLookup(lookup);
       finder.AddRequestedTags(requestedTags);
 
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Mon Oct 07 18:10:08 2024 +0200
@@ -137,7 +137,14 @@
                              DicomToJsonFormat format,
                              bool retrieveMetadata)
   {
-    ResourceFinder finder(level, true /* expand */);
+    ResponseContentFlags responseContent = ResponseContentFlags_Default;
+    
+    if (retrieveMetadata)
+    {
+      responseContent = static_cast<ResponseContentFlags>(static_cast<uint32_t>(responseContent) | ResponseContentFlags_Metadata);
+    }
+
+    ResourceFinder finder(level, responseContent);
     finder.SetOrthancId(level, identifier);
     finder.SetRetrieveMetadata(retrieveMetadata);
 
@@ -258,7 +265,7 @@
       std::set<DicomTag> requestedTags;
       OrthancRestApi::GetRequestedTags(requestedTags, call);
 
-      ResourceFinder finder(resourceType, expand);
+      ResourceFinder finder(resourceType, (expand ? ResponseContentFlags_Default : ResponseContentFlags_ID));
       finder.AddRequestedTags(requestedTags);
 
       if (call.HasArgument("limit") ||
@@ -364,7 +371,7 @@
        * EXPERIMENTAL VERSION
        **/
 
-      ResourceFinder finder(resourceType, true /* expand */);
+      ResourceFinder finder(resourceType, ResponseContentFlags_Default);
       finder.AddRequestedTags(requestedTags);
       finder.SetOrthancId(resourceType, call.GetUriComponent("id", ""));
 
@@ -3257,6 +3264,7 @@
     static const char* const KEY_PARENT_STUDY = "ParentStudy";            // New in Orthanc 1.12.5
     static const char* const KEY_PARENT_SERIES = "ParentSeries";          // New in Orthanc 1.12.5
     static const char* const KEY_QUERY_METADATA = "QueryMetadata";        // New in Orthanc 1.12.5
+    static const char* const KEY_RESPONSE_CONTENT = "ResponseContent";    // New in Orthanc 1.12.5
 
     if (call.IsDocumentation())
     {
@@ -3300,6 +3308,10 @@
                          "Limit the reported resources to descendants of this series (new in Orthanc 1.12.5)", true)
         .SetRequestField(KEY_QUERY_METADATA, RestApiCallDocumentation::Type_JsonObject,
                          "Associative array containing the filter on the values of the metadata (new in Orthanc 1.12.5)", true)
+        .SetRequestField(KEY_RESPONSE_CONTENT, RestApiCallDocumentation::Type_JsonListOfStrings,
+                         "Defines the content of response for each returned resource.  Allowed values are `MainDicomTags`, "
+                         "`Metadata`, `Children`, `Parent`, `Labels`, `Status`, `IsStable`, `Attachments`.  "
+                         "(new in Orthanc 1.12.5)", true)
         .AddAnswerType(MimeType_Json, "JSON array containing either the Orthanc identifiers, or detailed information "
                        "about the reported resources (if `Expand` argument is `true`)");
       return;
@@ -3350,6 +3362,12 @@
       throw OrthancException(ErrorCode_BadRequest, 
                              "Field \"" + std::string(KEY_REQUESTED_TAGS) + "\" must be an array");
     }
+    else if (request.isMember(KEY_RESPONSE_CONTENT) &&
+             request[KEY_RESPONSE_CONTENT].type() != Json::arrayValue)
+    {
+      throw OrthancException(ErrorCode_BadRequest, 
+                             "Field \"" + std::string(KEY_RESPONSE_CONTENT) + "\" must be an array");
+    }
     else if (request.isMember(KEY_LABELS) &&
              request[KEY_LABELS].type() != Json::arrayValue)
     {
@@ -3398,15 +3416,23 @@
        * EXPERIMENTAL VERSION
        **/
 
-      bool expand = false;
-      if (request.isMember(KEY_EXPAND))
+      ResponseContentFlags responseContent = ResponseContentFlags_ID;
+      
+      if (request.isMember(KEY_RESPONSE_CONTENT))
       {
-        expand = request[KEY_EXPAND].asBool();
+        for (Json::ArrayIndex i = 0; i < request[KEY_RESPONSE_CONTENT].size(); ++i)
+        {
+          responseContent = static_cast<ResponseContentFlags>(static_cast<uint32_t>(responseContent) | StringToResponseContent(request[KEY_RESPONSE_CONTENT][i].asString()));
+        }
+      }
+      else if (request.isMember(KEY_EXPAND) && request[KEY_EXPAND].asBool())
+      {
+        responseContent = ResponseContentFlags_Default;
       }
 
       const ResourceType level = StringToResourceType(request[KEY_LEVEL].asCString());
 
-      ResourceFinder finder(level, expand);
+      ResourceFinder finder(level, responseContent);
       finder.SetDatabaseLimits(context.GetDatabaseLimits(level));
 
       const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human);
@@ -3796,7 +3822,7 @@
        * EXPERIMENTAL VERSION
        **/
 
-      ResourceFinder finder(end, expand);
+      ResourceFinder finder(end, (expand ? ResponseContentFlags_Default : ResponseContentFlags_ID));
       finder.SetOrthancId(start, call.GetUriComponent("id", ""));
       finder.AddRequestedTags(requestedTags);
 
--- a/OrthancServer/Sources/OrthancWebDav.cpp	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/OrthancWebDav.cpp	Mon Oct 07 18:10:08 2024 +0200
@@ -1142,7 +1142,7 @@
 
       Visitor visitor(resources);
 
-      ResourceFinder finder(ResourceType_Study, false /* no expand */);
+      ResourceFinder finder(ResourceType_Study, ResponseContentFlags_ID);
       finder.SetDatabaseLookup(query);
       finder.Execute(visitor, GetContext());
     }
@@ -1220,7 +1220,7 @@
 
       Visitor visitor;
 
-      ResourceFinder finder(ResourceType_Study, false /* no expand */);
+      ResourceFinder finder(ResourceType_Study, ResponseContentFlags_ID);
       finder.SetDatabaseLookup(query);
       finder.Execute(visitor, context_);
 
@@ -1605,7 +1605,7 @@
          * EXPERIMENTAL VERSION
          **/
 
-        ResourceFinder finder(level, false /* don't expand */);
+        ResourceFinder finder(level, ResponseContentFlags_ID);
         finder.SetDatabaseLookup(query);
         finder.SetRetrieveMetadata(true);
 
@@ -1666,7 +1666,7 @@
                              ResourceType level,
                              const DatabaseLookup& query)
   {
-    ResourceFinder finder(level, true /* expand */);
+    ResourceFinder finder(level, ResponseContentFlags_Default);
     finder.SetDatabaseLookup(query);
 
     Json::Value expanded;
@@ -1773,7 +1773,7 @@
           /**
            * EXPERIMENTAL VERSION
            **/
-          ResourceFinder finder(ResourceType_Instance, false /* no expand */);
+          ResourceFinder finder(ResourceType_Instance, ResponseContentFlags_ID);
           finder.SetDatabaseLookup(query);
           finder.SetRetrieveMetadata(true);
           finder.SetRetrieveAttachments(true);
@@ -1913,7 +1913,7 @@
 
         DicomDeleteVisitor visitor(context_, level);
 
-        ResourceFinder finder(level, false /* no expand */);
+        ResourceFinder finder(level, ResponseContentFlags_ID);
         finder.SetDatabaseLookup(query);
         finder.Execute(visitor, context_);
         return true;
--- a/OrthancServer/Sources/ResourceFinder.cpp	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/ResourceFinder.cpp	Mon Oct 07 18:10:08 2024 +0200
@@ -210,15 +210,14 @@
   void ResourceFinder::Expand(Json::Value& target,
                               const FindResponse::Resource& resource,
                               ServerIndex& index,
-                              DicomToJsonFormat format,
-                              bool includeAllMetadata) const
+                              DicomToJsonFormat format) const
   {
     /**
      * This method closely follows "SerializeExpandedResource()" in
      * "ServerContext.cpp" from Orthanc 1.12.4.
      **/
 
-    if (!expand_)
+    if (responseContent_ == ResponseContentFlags_ID)
     {
       throw OrthancException(ErrorCode_BadSequenceOfCalls);
     }
@@ -233,28 +232,31 @@
     target["Type"] = GetResourceTypeText(resource.GetLevel(), false, true);
     target["ID"] = resource.GetIdentifier();
 
-    switch (resource.GetLevel())
+    if (responseContent_ & ResponseContentFlags_Parent)
     {
-      case ResourceType_Patient:
-        break;
+      switch (resource.GetLevel())
+      {
+        case ResourceType_Patient:
+          break;
 
-      case ResourceType_Study:
-        target["ParentPatient"] = resource.GetParentIdentifier();
-        break;
+        case ResourceType_Study:
+          target["ParentPatient"] = resource.GetParentIdentifier();
+          break;
 
-      case ResourceType_Series:
-        target["ParentStudy"] = resource.GetParentIdentifier();
-        break;
+        case ResourceType_Series:
+          target["ParentStudy"] = resource.GetParentIdentifier();
+          break;
 
-      case ResourceType_Instance:
-        target["ParentSeries"] = resource.GetParentIdentifier();
-        break;
+        case ResourceType_Instance:
+          target["ParentSeries"] = resource.GetParentIdentifier();
+          break;
 
-      default:
-        throw OrthancException(ErrorCode_InternalError);
+        default:
+          throw OrthancException(ErrorCode_InternalError);
+      }
     }
 
-    if (resource.GetLevel() != ResourceType_Instance)
+    if ((responseContent_ & ResponseContentFlags_Children) && (resource.GetLevel() != ResourceType_Instance))
     {
       const std::set<std::string>& children = resource.GetChildrenIdentifiers(GetChildResourceType(resource.GetLevel()));
 
@@ -292,52 +294,65 @@
 
       case ResourceType_Series:
       {
-        uint32_t expectedNumberOfInstances;
-        SeriesStatus status = GetSeriesStatus(expectedNumberOfInstances, resource);
-
-        target["Status"] = EnumerationToString(status);
-
-        static const char* const EXPECTED_NUMBER_OF_INSTANCES = "ExpectedNumberOfInstances";
+        if ((responseContent_ & ResponseContentFlags_Status) || (responseContent_ & ResponseContentFlags_MetadataLegacy) )
+        {
+          uint32_t expectedNumberOfInstances;
+          SeriesStatus status = GetSeriesStatus(expectedNumberOfInstances, resource);
+          
+          if (responseContent_ & ResponseContentFlags_Status )
+          {
+            target["Status"] = EnumerationToString(status);
+          }
 
-        if (status == SeriesStatus_Unknown)
-        {
-          target[EXPECTED_NUMBER_OF_INSTANCES] = Json::nullValue;
+          if (responseContent_ & ResponseContentFlags_MetadataLegacy)
+          {
+            static const char* const EXPECTED_NUMBER_OF_INSTANCES = "ExpectedNumberOfInstances";
+
+            if (status == SeriesStatus_Unknown)
+            {
+              target[EXPECTED_NUMBER_OF_INSTANCES] = Json::nullValue;
+            }
+            else
+            {
+              target[EXPECTED_NUMBER_OF_INSTANCES] = expectedNumberOfInstances;
+            }
+          }
         }
-        else
-        {
-          target[EXPECTED_NUMBER_OF_INSTANCES] = expectedNumberOfInstances;
-        }
-
         break;
       }
 
       case ResourceType_Instance:
       {
-        FileInfo info;
-        if (resource.LookupAttachment(info, FileContentType_Dicom))
+        if (responseContent_ & ResponseContentFlags_AttachmentsLegacy)
         {
-          target["FileSize"] = static_cast<Json::UInt64>(info.GetUncompressedSize());
-          target["FileUuid"] = info.GetUuid();
-        }
-        else
-        {
-          throw OrthancException(ErrorCode_InternalError);
+          FileInfo info;
+          if (resource.LookupAttachment(info, FileContentType_Dicom))
+          {
+            target["FileSize"] = static_cast<Json::UInt64>(info.GetUncompressedSize());
+            target["FileUuid"] = info.GetUuid();
+          }
+          else
+          {
+            throw OrthancException(ErrorCode_InternalError);
+          }
         }
 
-        static const char* const INDEX_IN_SERIES = "IndexInSeries";
-
-        std::string s;
-        uint32_t indexInSeries;
-        if (resource.LookupMetadata(s, ResourceType_Instance, MetadataType_Instance_IndexInSeries) &&
-            SerializationToolbox::ParseUnsignedInteger32(indexInSeries, s))
+        if (responseContent_ & ResponseContentFlags_MetadataLegacy)
         {
-          target[INDEX_IN_SERIES] = indexInSeries;
+          static const char* const INDEX_IN_SERIES = "IndexInSeries";
+
+          std::string s;
+          uint32_t indexInSeries;
+          if (resource.LookupMetadata(s, ResourceType_Instance, MetadataType_Instance_IndexInSeries) &&
+              SerializationToolbox::ParseUnsignedInteger32(indexInSeries, s))
+          {
+            target[INDEX_IN_SERIES] = indexInSeries;
+          }
+          else
+          {
+            target[INDEX_IN_SERIES] = Json::nullValue;
+          }
         }
-        else
-        {
-          target[INDEX_IN_SERIES] = Json::nullValue;
-        }
-
         break;
       }
 
@@ -346,28 +361,40 @@
     }
 
     std::string s;
-    if (resource.LookupMetadata(s, resource.GetLevel(), MetadataType_AnonymizedFrom))
+    if (responseContent_ & ResponseContentFlags_MetadataLegacy)
     {
-      target["AnonymizedFrom"] = s;
-    }
-
-    if (resource.LookupMetadata(s, resource.GetLevel(), MetadataType_ModifiedFrom))
-    {
-      target["ModifiedFrom"] = s;
-    }
+      if (resource.LookupMetadata(s, resource.GetLevel(), MetadataType_AnonymizedFrom))
+      {
+        target["AnonymizedFrom"] = s;
+      }
 
-    if (resource.GetLevel() == ResourceType_Patient ||
-        resource.GetLevel() == ResourceType_Study ||
-        resource.GetLevel() == ResourceType_Series)
-    {
-      target["IsStable"] = !index.IsUnstableResource(resource.GetLevel(), resource.GetInternalId());
+      if (resource.LookupMetadata(s, resource.GetLevel(), MetadataType_ModifiedFrom))
+      {
+        target["ModifiedFrom"] = s;
+      }
 
-      if (resource.LookupMetadata(s, resource.GetLevel(), MetadataType_LastUpdate))
+      if (resource.GetLevel() == ResourceType_Patient ||
+          resource.GetLevel() == ResourceType_Study ||
+          resource.GetLevel() == ResourceType_Series)
       {
-        target["LastUpdate"] = s;
+        if (resource.LookupMetadata(s, resource.GetLevel(), MetadataType_LastUpdate))
+        {
+          target["LastUpdate"] = s;
+        }
       }
     }
 
+    if (responseContent_ & ResponseContentFlags_IsStable)
+    {
+      if (resource.GetLevel() == ResourceType_Patient ||
+          resource.GetLevel() == ResourceType_Study ||
+          resource.GetLevel() == ResourceType_Series)
+      {
+        target["IsStable"] = !index.IsUnstableResource(resource.GetLevel(), resource.GetInternalId());
+      }
+    }
+
+    if (responseContent_ & ResponseContentFlags_MainDicomTags)
     {
       DicomMap allMainDicomTags;
       resource.GetMainDicomTags(allMainDicomTags, resource.GetLevel());
@@ -396,6 +423,7 @@
       }
     }
 
+    if (responseContent_ & ResponseContentFlags_Labels)
     {
       Json::Value labels = Json::arrayValue;
 
@@ -408,7 +436,7 @@
       target["Labels"] = labels;
     }
 
-    if (includeAllMetadata)  // new in Orthanc 1.12.4
+    if (responseContent_ & ResponseContentFlags_Metadata)  // new in Orthanc 1.12.4
     {
       const std::map<MetadataType, std::string>& m = resource.GetMetadata(resource.GetLevel());
 
@@ -421,6 +449,26 @@
 
       target["Metadata"] = metadata;
     }
+
+    if (responseContent_ & ResponseContentFlags_Attachments)  // new in Orthanc 1.12.5
+    {
+      const std::map<FileContentType, FileInfo>& attachments = resource.GetAttachments();
+
+      target["Attachments"] = Json::arrayValue;
+
+      for (std::map<FileContentType, FileInfo>::const_iterator it = attachments.begin(); it != attachments.end(); ++it)
+      {
+        Json::Value attachment = Json::objectValue;    
+        attachment["Uuid"] = it->second.GetUuid();
+        attachment["ContentType"] = it->second.GetContentType();
+        attachment["UncompressedSize"] = Json::Value::UInt64(it->second.GetUncompressedSize());
+        attachment["CompressedSize"] = Json::Value::UInt64(it->second.GetCompressedSize());
+        attachment["UncompressedMD5"] = it->second.GetUncompressedMD5();
+        attachment["CompressedMD5"] = it->second.GetCompressedMD5();
+
+        target["Attachments"].append(attachment);
+      }
+    }
   }
 
 
@@ -473,7 +521,7 @@
 
 
   ResourceFinder::ResourceFinder(ResourceType level,
-                                 bool expand) :
+                                 ResponseContentFlags responseContent) :
     request_(level),
     databaseLimits_(0),
     isSimpleLookup_(true),
@@ -482,7 +530,7 @@
     hasLimitsCount_(false),
     limitsSince_(0),
     limitsCount_(0),
-    expand_(expand),
+    responseContent_(responseContent),
     allowStorageAccess_(true),
     isWarning002Enabled_(false),
     isWarning004Enabled_(false),
@@ -495,40 +543,43 @@
       isWarning005Enabled_ = lock.GetConfiguration().IsWarningEnabled(Warnings_005_RequestingTagFromLowerResourceLevel);
     }
 
-
     UpdateRequestLimits();
 
-    if (expand)
-    {
-      request_.SetRetrieveMainDicomTags(true);
-      request_.SetRetrieveMetadata(true);
-      request_.SetRetrieveLabels(true);
+    request_.SetRetrieveMainDicomTags(responseContent_ & ResponseContentFlags_MainDicomTags);
+    request_.SetRetrieveMetadata((responseContent_ & ResponseContentFlags_Metadata) || (responseContent_ & ResponseContentFlags_MetadataLegacy));
+    request_.SetRetrieveLabels(responseContent_ & ResponseContentFlags_Labels);
 
-      switch (level)
-      {
-        case ResourceType_Patient:
-          request_.GetChildrenSpecification(ResourceType_Study).SetRetrieveIdentifiers(true);
-          break;
+    switch (level)
+    {
+      case ResourceType_Patient:
+        request_.GetChildrenSpecification(ResourceType_Study).SetRetrieveIdentifiers(responseContent_ & ResponseContentFlags_Children);
+        request_.SetRetrieveAttachments(responseContent_ & ResponseContentFlags_Attachments); 
+        break;
+
+      case ResourceType_Study:
+        request_.GetChildrenSpecification(ResourceType_Series).SetRetrieveIdentifiers(responseContent_ & ResponseContentFlags_Children);
+        request_.SetRetrieveParentIdentifier(responseContent_ & ResponseContentFlags_Parent);
+        request_.SetRetrieveAttachments(responseContent_ & ResponseContentFlags_Attachments); 
+        break;
 
-        case ResourceType_Study:
-          request_.GetChildrenSpecification(ResourceType_Series).SetRetrieveIdentifiers(true);
-          request_.SetRetrieveParentIdentifier(true);
-          break;
-
-        case ResourceType_Series:
+      case ResourceType_Series:
+        if (responseContent_ & ResponseContentFlags_Status)
+        {
           request_.GetChildrenSpecification(ResourceType_Instance).AddMetadata(MetadataType_Instance_IndexInSeries); // required for the SeriesStatus
-          request_.GetChildrenSpecification(ResourceType_Instance).SetRetrieveIdentifiers(true);
-          request_.SetRetrieveParentIdentifier(true);
-          break;
+        }
+        request_.GetChildrenSpecification(ResourceType_Instance).SetRetrieveIdentifiers(responseContent_ & ResponseContentFlags_Children);
+        request_.SetRetrieveParentIdentifier(responseContent_ & ResponseContentFlags_Parent);
+        request_.SetRetrieveAttachments(responseContent_ & ResponseContentFlags_Attachments); 
+        break;
 
-        case ResourceType_Instance:
-          request_.SetRetrieveAttachments(true); // for FileSize & FileUuid
-          request_.SetRetrieveParentIdentifier(true);
-          break;
+      case ResourceType_Instance:
+        request_.SetRetrieveAttachments((responseContent_ & ResponseContentFlags_AttachmentsLegacy) // for FileSize & FileUuid
+                                        || (responseContent_ & ResponseContentFlags_Attachments)); 
+        request_.SetRetrieveParentIdentifier(true);
+        break;
 
-        default:
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-      }
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
   }
 
@@ -1126,10 +1177,10 @@
       virtual void Apply(const FindResponse::Resource& resource,
                          const DicomMap& requestedTags) ORTHANC_OVERRIDE
       {
-        if (that_.expand_)
+        if (that_.responseContent_ != ResponseContentFlags_ID)
         {
           Json::Value item;
-          that_.Expand(item, resource, index_, format_, includeAllMetadata_);
+          that_.Expand(item, resource, index_, format_);
 
           if (hasRequestedTags_)
           {
--- a/OrthancServer/Sources/ResourceFinder.h	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/ResourceFinder.h	Mon Oct 07 18:10:08 2024 +0200
@@ -65,7 +65,7 @@
     bool                             hasLimitsCount_;
     uint64_t                         limitsSince_;
     uint64_t                         limitsCount_;
-    bool                             expand_;
+    ResponseContentFlags             responseContent_;
     bool                             allowStorageAccess_;
     std::set<DicomTag>               requestedTags_;
     std::set<DicomTag>               requestedComputedTags_;
@@ -103,7 +103,7 @@
 
   public:
     ResourceFinder(ResourceType level,
-                   bool expand);
+                   ResponseContentFlags responseContent);
 
     void SetDatabaseLimits(uint64_t limits);
 
@@ -184,8 +184,7 @@
     void Expand(Json::Value& target,
                 const FindResponse::Resource& resource,
                 ServerIndex& index,
-                DicomToJsonFormat format,
-                bool includeAllMetadata /* Same as: ExpandResourceFlags_IncludeAllMetadata */) const;
+                DicomToJsonFormat format) const;
 
     void Execute(IVisitor& visitor,
                  ServerContext& context) const;
--- a/OrthancServer/Sources/ServerEnumerations.cpp	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/ServerEnumerations.cpp	Mon Oct 07 18:10:08 2024 +0200
@@ -616,4 +616,45 @@
         throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
   }
-}
+
+  ResponseContentFlags StringToResponseContent(const std::string& value)
+  {
+    if (value == "MainDicomTags")
+    {
+      return ResponseContentFlags_MainDicomTags;
+    }
+    else if (value == "Metadata")
+    {
+      return ResponseContentFlags_Metadata;
+    }
+    else if (value == "Status")
+    {
+      return ResponseContentFlags_Status;
+    }
+    else if (value == "Parent")
+    {
+      return ResponseContentFlags_Parent;
+    }
+    else if (value == "Children")
+    {
+      return ResponseContentFlags_Children;
+    }
+    else if (value == "Labels")
+    {
+      return ResponseContentFlags_Labels;
+    }
+    else if (value == "Attachments")
+    {
+      return ResponseContentFlags_Attachments;
+    }
+    else if (value == "IsStable")
+    {
+      return ResponseContentFlags_IsStable;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange,
+                             "Unrecognized value for \"ResponseContent\": " + value);
+    }    
+  }
+}
\ No newline at end of file
--- a/OrthancServer/Sources/ServerEnumerations.h	Mon Oct 07 15:19:26 2024 +0200
+++ b/OrthancServer/Sources/ServerEnumerations.h	Mon Oct 07 18:10:08 2024 +0200
@@ -121,6 +121,31 @@
     ConstraintType_List
   };
 
+  enum ResponseContentFlags
+  {
+    ResponseContentFlags_ID                   = (1 << 0),
+    ResponseContentFlags_MainDicomTags        = (1 << 1),
+    ResponseContentFlags_MetadataLegacy       = (1 << 2),    // when "Expand": true -> all metadata are included at root level
+    ResponseContentFlags_AttachmentsLegacy    = (1 << 3),    // when "Expand": true -> include attachments info at instance level
+    ResponseContentFlags_Metadata             = (1 << 4),    // all metadata are listed in a "Metadata" field
+    ResponseContentFlags_Attachments          = (1 << 5),    // all attachments are listed in a "Attachments" field
+    ResponseContentFlags_Status               = (1 << 6),
+    ResponseContentFlags_Parent               = (1 << 7),
+    ResponseContentFlags_Children             = (1 << 8),
+    ResponseContentFlags_Labels               = (1 << 9),
+    ResponseContentFlags_IsStable             = (1 << 10),
+
+    // Some predefined combinations
+    ResponseContentFlags_Default  = (ResponseContentFlags_ID |
+                                     ResponseContentFlags_MainDicomTags |
+                                     ResponseContentFlags_MetadataLegacy |
+                                     ResponseContentFlags_AttachmentsLegacy | 
+                                     ResponseContentFlags_Status | 
+                                     ResponseContentFlags_Parent | 
+                                     ResponseContentFlags_Children | 
+                                     ResponseContentFlags_Labels |
+                                     ResponseContentFlags_IsStable)  // equivalent to "Expand": true
+  };
 
   /**
    * WARNING: Do not change the explicit values in the enumerations
@@ -250,6 +275,8 @@
 
   Verbosity StringToVerbosity(const std::string& str);
 
+  ResponseContentFlags StringToResponseContent(const std::string& str);
+
   std::string EnumerationToString(FileContentType type);
 
   std::string GetFileContentMime(FileContentType type);