changeset 4417:a4518adede59

openapi for plugins and jobs
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 28 Dec 2020 17:40:35 +0100
parents 0b27841950d5
children 9d6fa3da8f00
files OrthancFramework/Sources/RestApi/RestApi.cpp OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp
diffstat 5 files changed, 141 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/RestApi/RestApi.cpp	Mon Dec 28 16:49:17 2020 +0100
+++ b/OrthancFramework/Sources/RestApi/RestApi.cpp	Mon Dec 28 17:40:35 2020 +0100
@@ -359,8 +359,10 @@
       virtual bool HandleCall(RestApiCall& call,
                               const std::set<std::string> uriArgumentsNames) ORTHANC_OVERRIDE
       {
+        const std::string path = Toolbox::FlattenUri(call.GetFullUri());
+
         Json::Value v;
-        if (call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames))
+        if (call.GetDocumentation().FormatOpenApi(v, uriArgumentsNames, path))
         {
           std::string method;
           
@@ -386,8 +388,6 @@
               throw OrthancException(ErrorCode_ParameterOutOfRange);
           }
           
-          const std::string path = Toolbox::FlattenUri(call.GetFullUri());
-
           if ((paths_.isMember(path) &&
                paths_[path].type() != Json::objectValue) ||
               paths_[path].isMember(method))
--- a/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp	Mon Dec 28 16:49:17 2020 +0100
+++ b/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp	Mon Dec 28 17:40:35 2020 +0100
@@ -307,7 +307,8 @@
 
 
   bool RestApiCallDocumentation::FormatOpenApi(Json::Value& target,
-                                               const std::set<std::string>& expectedUriArguments) const
+                                               const std::set<std::string>& expectedUriArguments,
+                                               const std::string& uri) const
   {
     if (summary_.empty() &&
         description_.empty())
@@ -362,6 +363,13 @@
               p["description"] = field->second.GetDescription();
               schema["properties"][field->first] = p;         
             }        
+
+            if (!it->second.empty() &&
+                answerFields_.size() > 0)
+            {
+              LOG(WARNING) << "The JSON description will not be visible if the fields of the JSON request are detailed: "
+                           << EnumerationToString(method_) << " " << uri;
+            }
           }
         }
       }
@@ -383,7 +391,14 @@
             TypeToSchema(p, field->second.GetType());
             p["description"] = field->second.GetDescription();
             schema["properties"][field->first] = p;         
-          }        
+          }
+
+          if (!it->second.empty() &&
+              answerFields_.size() > 0)
+          {
+            LOG(WARNING) << "The JSON description will not be visible if the fields of the JSON answer are detailed: "
+                         << EnumerationToString(method_) << " " << uri;
+          }
         }
       }
       
--- a/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h	Mon Dec 28 16:49:17 2020 +0100
+++ b/OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h	Mon Dec 28 17:40:35 2020 +0100
@@ -184,7 +184,8 @@
     }
 
     bool FormatOpenApi(Json::Value& target,
-                       const std::set<std::string>& expectedUriArguments) const;
+                       const std::set<std::string>& expectedUriArguments,
+                       const std::string& uri /* only used in logs */) const;
 
     bool HasSummary() const
     {
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp	Mon Dec 28 16:49:17 2020 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp	Mon Dec 28 17:40:35 2020 +0100
@@ -214,7 +214,9 @@
                        "In asynchronous mode, the priority of the job. The lower the value, the higher the priority.", false)
       .AddAnswerType(MimeType_Zip, "In synchronous mode, the ZIP file containing the archive")
       .AddAnswerType(MimeType_Json, "In asynchronous mode, information about the job that has been submitted to "
-                     "generate the archive: https://book.orthanc-server.com/users/advanced-rest.html#jobs");
+                     "generate the archive: https://book.orthanc-server.com/users/advanced-rest.html#jobs")
+      .SetAnswerField("ID", RestApiCallDocumentation::Type_String, "Identifier of the job")
+      .SetAnswerField("Path", RestApiCallDocumentation::Type_String, "Path to access the job in the REST API");
 
     if (isMedia)
     {
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp	Mon Dec 28 16:49:17 2020 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp	Mon Dec 28 17:40:35 2020 +0100
@@ -322,6 +322,17 @@
 
   static void ListPlugins(RestApiGetCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      call.GetDocumentation()
+        .SetTag("System")
+        .SetSummary("List plugins")
+        .SetDescription("List all the installed plugins")
+        .AddAnswerType(MimeType_Json, "JSON array containing the identifiers of the installed plugins")
+        .SetHttpGetSample("https://demo.orthanc-server.com/plugins", true);
+      return;
+    }
+
     Json::Value v = Json::arrayValue;
 
     v.append("explorer.js");
@@ -346,6 +357,18 @@
 
   static void GetPlugin(RestApiGetCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      call.GetDocumentation()
+        .SetTag("System")
+        .SetSummary("Get plugin")
+        .SetDescription("Get system information about the plugin whose identifier is provided in the URL")
+        .SetUriArgument("id", "Identifier of the job of interest")
+        .AddAnswerType(MimeType_Json, "JSON object containing information about the plugin")
+        .SetHttpGetSample("https://demo.orthanc-server.com/plugins/dicom-web", true);
+      return;
+    }
+
     if (!OrthancRestApi::GetContext(call).HasPlugins())
     {
       return;
@@ -429,6 +452,20 @@
 
   static void ListJobs(RestApiGetCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      call.GetDocumentation()
+        .SetTag("Jobs")
+        .SetSummary("List jobs")
+        .SetDescription("List all the available jobs")
+        .SetHttpGetArgument("expand", RestApiCallDocumentation::Type_String,
+                            "If present, retrieve detailed information about the individual jobs", false)
+        .AddAnswerType(MimeType_Json, "JSON array containing either the jobs identifiers, or detailed information "
+                       "about the reported jobs (if `expand` argument is provided)")
+        .SetTruncatedJsonHttpGetSample("https://demo.orthanc-server.com/jobs", 3);
+      return;
+    }
+
     bool expand = call.HasArgument("expand");
 
     Json::Value v = Json::arrayValue;
@@ -460,6 +497,36 @@
 
   static void GetJobInfo(RestApiGetCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      Json::Value sample;
+      sample["CompletionTime"] = "20201227T161842.520129";
+      sample["Content"]["ArchiveSizeMB"] = 22;
+      sample["Content"]["Description"] = "REST API";
+      sample["Content"]["InstancesCount"] = 232;
+      sample["Content"]["UncompressedSizeMB"] = 64;
+      sample["CreationTime"] = "20201227T161836.428311";
+      sample["EffectiveRuntime"] = 6.0810000000000004;
+      sample["ErrorCode"] = 0;
+      sample["ErrorDescription"] = "Success";
+      sample["ID"] = "645ecb02-7c0e-4465-b767-df873222dcfb";
+      sample["Priority"] = 0;
+      sample["Progress"] = 100;
+      sample["State"] = "Success";
+      sample["Timestamp"] = "20201228T160340.253201";
+      sample["Type"] = "Media";
+      
+      call.GetDocumentation()
+        .SetTag("Jobs")
+        .SetSummary("Get job")
+        .SetDescription("Retrieve detailed information about the job whose identifier is provided in the URL: "
+                        "https://book.orthanc-server.com/users/advanced-rest.html#jobs")
+        .SetUriArgument("id", "Identifier of the job of interest")
+        .AddAnswerType(MimeType_Json, "JSON object detailing the job")
+        .SetSample(sample);
+      return;
+    }
+
     std::string id = call.GetUriComponent("id", "");
 
     JobInfo info;
@@ -474,6 +541,19 @@
 
   static void GetJobOutput(RestApiGetCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      call.GetDocumentation()
+        .SetTag("Jobs")
+        .SetSummary("Get job output")
+        .SetDescription("Retrieve some output produced by a job. As of Orthanc 1.8.2, only the jobs that generate a "
+                        "DICOMDIR media or a ZIP archive provide such an output (with `key` equals to `archive`).")
+        .SetUriArgument("id", "Identifier of the job of interest")
+        .SetUriArgument("key", "Name of the output of interest")
+        .AddAnswerType(MimeType_Binary, "Content of the output of the job");
+      return;
+    }
+
     std::string job = call.GetUriComponent("id", "");
     std::string key = call.GetUriComponent("key", "");
 
@@ -504,6 +584,42 @@
   template <JobAction action>
   static void ApplyJobAction(RestApiPostCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      std::string verb;
+      switch (action)
+      {
+        case JobAction_Cancel:
+          verb = "Cancel";
+          break;
+
+        case JobAction_Pause:
+          verb = "Pause";
+          break;
+ 
+        case JobAction_Resubmit:
+          verb = "Resubmit";
+          break;
+
+        case JobAction_Resume:
+          verb = "Resume";
+          break;
+
+        default:
+          throw OrthancException(ErrorCode_InternalError);
+      }      
+      
+      call.GetDocumentation()
+        .SetTag("Jobs")
+        .SetSummary(verb + " job")
+        .SetDescription(verb + " the job whose identifier is provided in the URL. Check out the "
+                        "Orthanc Book for more information about the state machine applicable to jobs: "
+                        "https://book.orthanc-server.com/users/advanced-rest.html#jobs")
+        .SetUriArgument("id", "Identifier of the job of interest")
+        .AddAnswerType(MimeType_Json, "Empty JSON object in the case of a success");
+      return;
+    }
+
     std::string id = call.GetUriComponent("id", "");
 
     bool ok = false;