comparison OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp @ 4416:0b27841950d5

openapi about creation of zip/media archives
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 28 Dec 2020 16:49:17 +0100
parents 05b8fd21089c
children a4518adede59
comparison
equal deleted inserted replaced
4415:b50410d0e98c 4416:0b27841950d5
192 { 192 {
193 OrthancRestApi::SubmitGenericJob(output, context, job.release(), false, priority); 193 OrthancRestApi::SubmitGenericJob(output, context, job.release(), false, priority);
194 } 194 }
195 } 195 }
196 196
197
198 static void DocumentPostArguments(RestApiPostCall& call,
199 bool isMedia,
200 bool defaultExtended)
201 {
202 call.GetDocumentation()
203 .SetRequestField("Synchronous", RestApiCallDocumentation::Type_Boolean,
204 "If `true`, create the archive in synchronous mode, which means that the HTTP answer will directly "
205 "contain the ZIP file. This is the default, easy behavior, but it is *not* be desirable to archive "
206 "large amount of data, as it might lead to network timeouts.", false)
207 .SetRequestField("Asynchronous", RestApiCallDocumentation::Type_Boolean,
208 "If `true`, create the archive in asynchronous mode, which means that a job is submitted to create "
209 "the archive in background. Prefer this flavor wherever possible.", false)
210 .SetRequestField(KEY_TRANSCODE, RestApiCallDocumentation::Type_String,
211 "If present, the DICOM files in the archive will be transcoded to the provided "
212 "transfer syntax: https://book.orthanc-server.com/faq/transcoding.html", false)
213 .SetRequestField("Priority", RestApiCallDocumentation::Type_Number,
214 "In asynchronous mode, the priority of the job. The lower the value, the higher the priority.", false)
215 .AddAnswerType(MimeType_Zip, "In synchronous mode, the ZIP file containing the archive")
216 .AddAnswerType(MimeType_Json, "In asynchronous mode, information about the job that has been submitted to "
217 "generate the archive: https://book.orthanc-server.com/users/advanced-rest.html#jobs");
218
219 if (isMedia)
220 {
221 call.GetDocumentation().SetRequestField(
222 KEY_EXTENDED, RestApiCallDocumentation::Type_Boolean, "If `true`, will include additional "
223 "tags such as `SeriesDescription`, leading to a so-called *extended DICOMDIR*. Default value is " +
224 std::string(defaultExtended ? "`true`" : "`false`") + ".", false);
225 }
226 }
227
197 228
198 template <bool IS_MEDIA, 229 template <bool IS_MEDIA,
199 bool DEFAULT_IS_EXTENDED /* only makes sense for media (i.e. not ZIP archives) */ > 230 bool DEFAULT_IS_EXTENDED /* only makes sense for media (i.e. not ZIP archives) */ >
200 static void CreateBatch(RestApiPostCall& call) 231 static void CreateBatch(RestApiPostCall& call)
201 { 232 {
233 if (call.IsDocumentation())
234 {
235 DocumentPostArguments(call, IS_MEDIA, DEFAULT_IS_EXTENDED);
236 std::string m = (IS_MEDIA ? "DICOMDIR media" : "ZIP archive");
237 call.GetDocumentation()
238 .SetTag("System")
239 .SetSummary("Create " + m)
240 .SetDescription("Create a " + m + " containing the DICOM resources (patients, studies, series, or instances) "
241 "whose Orthanc identifiers are provided in the body")
242 .SetRequestField("Resources", RestApiCallDocumentation::Type_JsonListOfStrings,
243 "The list of Orthanc identifiers of interest.", false);
244 return;
245 }
246
202 ServerContext& context = OrthancRestApi::GetContext(call); 247 ServerContext& context = OrthancRestApi::GetContext(call);
203 248
204 Json::Value body; 249 Json::Value body;
205 if (call.ParseJsonRequest(body)) 250 if (call.ParseJsonRequest(body))
206 { 251 {
226 "Expected a list of resources to archive in the body"); 271 "Expected a list of resources to archive in the body");
227 } 272 }
228 } 273 }
229 274
230 275
231 template <bool IS_MEDIA, 276 template <bool IS_MEDIA>
232 bool DEFAULT_IS_EXTENDED /* only makes sense for media (i.e. not ZIP archives) */ >
233 static void CreateSingleGet(RestApiGetCall& call) 277 static void CreateSingleGet(RestApiGetCall& call)
234 { 278 {
279 if (call.IsDocumentation())
280 {
281 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
282 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
283 std::string m = (IS_MEDIA ? "DICOMDIR media" : "ZIP archive");
284 call.GetDocumentation()
285 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
286 .SetSummary("Create " + m)
287 .SetDescription("Synchronously create a " + m + " containing the DICOM " + r +
288 " whose Orthanc identifier is provided in the URL. This flavor is synchronous, "
289 "which might *not* be desirable to archive large amount of data, as it might "
290 "lead to network timeouts. Prefer the asynchronous version using `POST` method.")
291 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest")
292 .SetHttpGetArgument("transcode", RestApiCallDocumentation::Type_String,
293 "If present, the DICOM files in the archive will be transcoded to the provided "
294 "transfer syntax: https://book.orthanc-server.com/faq/transcoding.html", false)
295 .AddAnswerType(MimeType_Zip, "ZIP file containing the archive");
296 if (IS_MEDIA)
297 {
298 call.GetDocumentation().SetHttpGetArgument(
299 "extended", RestApiCallDocumentation::Type_String,
300 "If present, will include additional tags such as `SeriesDescription`, leading to a so-called *extended DICOMDIR*", false);
301 }
302 return;
303 }
304
235 ServerContext& context = OrthancRestApi::GetContext(call); 305 ServerContext& context = OrthancRestApi::GetContext(call);
236 306
237 std::string id = call.GetUriComponent("id", ""); 307 std::string id = call.GetUriComponent("id", "");
238 308
239 bool extended; 309 bool extended;
258 SubmitJob(call.GetOutput(), context, job, 0 /* priority */, 328 SubmitJob(call.GetOutput(), context, job, 0 /* priority */,
259 true /* synchronous */, id + ".zip"); 329 true /* synchronous */, id + ".zip");
260 } 330 }
261 331
262 332
263 template <bool IS_MEDIA, 333 template <bool IS_MEDIA>
264 bool DEFAULT_IS_EXTENDED /* only makes sense for media (i.e. not ZIP archives) */ >
265 static void CreateSinglePost(RestApiPostCall& call) 334 static void CreateSinglePost(RestApiPostCall& call)
266 { 335 {
336 if (call.IsDocumentation())
337 {
338 DocumentPostArguments(call, IS_MEDIA, false /* not extended by default */);
339 ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
340 std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
341 std::string m = (IS_MEDIA ? "DICOMDIR media" : "ZIP archive");
342 call.GetDocumentation()
343 .SetTag(GetResourceTypeText(t, true /* plural */, true /* upper case */))
344 .SetSummary("Create " + m)
345 .SetDescription("Create a " + m + " containing the DICOM " + r +
346 " whose Orthanc identifier is provided in the URL")
347 .SetUriArgument("id", "Orthanc identifier of the " + r + " of interest");
348 return;
349 }
350
267 ServerContext& context = OrthancRestApi::GetContext(call); 351 ServerContext& context = OrthancRestApi::GetContext(call);
268 352
269 std::string id = call.GetUriComponent("id", ""); 353 std::string id = call.GetUriComponent("id", "");
270 354
271 Json::Value body; 355 Json::Value body;
273 { 357 {
274 bool synchronous, extended, transcode; 358 bool synchronous, extended, transcode;
275 DicomTransferSyntax transferSyntax; 359 DicomTransferSyntax transferSyntax;
276 int priority; 360 int priority;
277 GetJobParameters(synchronous, extended, transcode, transferSyntax, 361 GetJobParameters(synchronous, extended, transcode, transferSyntax,
278 priority, body, DEFAULT_IS_EXTENDED); 362 priority, body, false /* by default, not extented */);
279 363
280 std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended)); 364 std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended));
281 job->AddResource(id); 365 job->AddResource(id);
282 366
283 if (transcode) 367 if (transcode)
294 } 378 }
295 379
296 380
297 void OrthancRestApi::RegisterArchive() 381 void OrthancRestApi::RegisterArchive()
298 { 382 {
299 Register("/patients/{id}/archive", 383 Register("/patients/{id}/archive", CreateSingleGet<false /* ZIP */>);
300 CreateSingleGet<false /* ZIP */, false /* extended makes no sense in ZIP */>); 384 Register("/patients/{id}/archive", CreateSinglePost<false /* ZIP */>);
301 Register("/studies/{id}/archive", 385 Register("/patients/{id}/media", CreateSingleGet<true /* media */>);
302 CreateSingleGet<false /* ZIP */, false /* extended makes no sense in ZIP */>); 386 Register("/patients/{id}/media", CreateSinglePost<true /* media */>);
303 Register("/series/{id}/archive", 387 Register("/series/{id}/archive", CreateSingleGet<false /* ZIP */>);
304 CreateSingleGet<false /* ZIP */, false /* extended makes no sense in ZIP */>); 388 Register("/series/{id}/archive", CreateSinglePost<false /* ZIP */>);
305 389 Register("/series/{id}/media", CreateSingleGet<true /* media */>);
306 Register("/patients/{id}/archive", 390 Register("/series/{id}/media", CreateSinglePost<true /* media */>);
307 CreateSinglePost<false /* ZIP */, false /* extended makes no sense in ZIP */>); 391 Register("/studies/{id}/archive", CreateSingleGet<false /* ZIP */>);
308 Register("/studies/{id}/archive", 392 Register("/studies/{id}/archive", CreateSinglePost<false /* ZIP */>);
309 CreateSinglePost<false /* ZIP */, false /* extended makes no sense in ZIP */>); 393 Register("/studies/{id}/media", CreateSingleGet<true /* media */>);
310 Register("/series/{id}/archive", 394 Register("/studies/{id}/media", CreateSinglePost<true /* media */>);
311 CreateSinglePost<false /* ZIP */, false /* extended makes no sense in ZIP */>);
312
313 Register("/patients/{id}/media",
314 CreateSingleGet<true /* media */, false /* not extended by default */>);
315 Register("/studies/{id}/media",
316 CreateSingleGet<true /* media */, false /* not extended by default */>);
317 Register("/series/{id}/media",
318 CreateSingleGet<true /* media */, false /* not extended by default */>);
319
320 Register("/patients/{id}/media",
321 CreateSinglePost<true /* media */, false /* not extended by default */>);
322 Register("/studies/{id}/media",
323 CreateSinglePost<true /* media */, false /* not extended by default */>);
324 Register("/series/{id}/media",
325 CreateSinglePost<true /* media */, false /* not extended by default */>);
326 395
327 Register("/tools/create-archive", 396 Register("/tools/create-archive",
328 CreateBatch<false /* ZIP */, false /* extended makes no sense in ZIP */>); 397 CreateBatch<false /* ZIP */, false /* extended makes no sense in ZIP */>);
329 Register("/tools/create-media", 398 Register("/tools/create-media",
330 CreateBatch<true /* media */, false /* not extended by default */>); 399 CreateBatch<true /* media */, false /* not extended by default */>);