# HG changeset patch # User Sebastien Jodogne # Date 1609173635 -3600 # Node ID a4518adede595d4fadca4b0afad972d92fd33388 # Parent 0b27841950d519b0a39a8b88a98751c892d57dfe openapi for plugins and jobs diff -r 0b27841950d5 -r a4518adede59 OrthancFramework/Sources/RestApi/RestApi.cpp --- 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 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)) diff -r 0b27841950d5 -r a4518adede59 OrthancFramework/Sources/RestApi/RestApiCallDocumentation.cpp --- 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& expectedUriArguments) const + const std::set& 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; + } } } diff -r 0b27841950d5 -r a4518adede59 OrthancFramework/Sources/RestApi/RestApiCallDocumentation.h --- 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& expectedUriArguments) const; + const std::set& expectedUriArguments, + const std::string& uri /* only used in logs */) const; bool HasSummary() const { diff -r 0b27841950d5 -r a4518adede59 OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp --- 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) { diff -r 0b27841950d5 -r a4518adede59 OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp --- 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 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;