diff --git a/services/api-server/openapi.json b/services/api-server/openapi.json index 3b74b6be1ed..63410d9274e 100644 --- a/services/api-server/openapi.json +++ b/services/api-server/openapi.json @@ -231,11 +231,11 @@ "content": { "application/json": { "schema": { - "title": "Response List Files V0 Files Get", - "type": "array", "items": { "$ref": "#/components/schemas/File" - } + }, + "type": "array", + "title": "Response List Files V0 Files Get" } } } @@ -320,8 +320,8 @@ { "required": false, "schema": { - "title": "Content-Length", - "type": "string" + "type": "string", + "title": "Content-Length" }, "name": "content-length", "in": "header" @@ -438,9 +438,9 @@ { "required": true, "schema": { - "title": "File Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "File Id" }, "name": "file_id", "in": "path" @@ -546,9 +546,9 @@ { "required": true, "schema": { - "title": "File Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "File Id" }, "name": "file_id", "in": "path" @@ -618,6 +618,22 @@ } } }, + "200": { + "description": "Returns a arbitrary binary data", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, "422": { "description": "Validation Error", "content": { @@ -650,11 +666,11 @@ "content": { "application/json": { "schema": { - "title": "Response List Solvers V0 Solvers Get", - "type": "array", "items": { "$ref": "#/components/schemas/Solver" - } + }, + "type": "array", + "title": "Response List Solvers V0 Solvers Get" } } } @@ -741,11 +757,11 @@ "content": { "application/json": { "schema": { - "title": "Response List Solvers Releases V0 Solvers Releases Get", - "type": "array", "items": { "$ref": "#/components/schemas/Solver" - } + }, + "type": "array", + "title": "Response List Solvers Releases V0 Solvers Releases Get" } } } @@ -830,9 +846,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -939,9 +955,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -953,11 +969,11 @@ "content": { "application/json": { "schema": { - "title": "Response List Solver Releases V0 Solvers Solver Key Releases Get", - "type": "array", "items": { "$ref": "#/components/schemas/Solver" - } + }, + "type": "array", + "title": "Response List Solver Releases V0 Solvers Solver Key Releases Get" } } } @@ -1052,9 +1068,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1062,9 +1078,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1171,9 +1187,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1181,9 +1197,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1290,9 +1306,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1300,9 +1316,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1314,11 +1330,11 @@ "content": { "application/json": { "schema": { - "title": "Response List Jobs V0 Solvers Solver Key Releases Version Jobs Get", - "type": "array", "items": { "$ref": "#/components/schemas/Job" - } + }, + "type": "array", + "title": "Response List Jobs V0 Solvers Solver Key Releases Version Jobs Get" } } } @@ -1421,9 +1437,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1431,9 +1447,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1560,9 +1576,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1570,9 +1586,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1580,9 +1596,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -1590,9 +1606,9 @@ { "required": false, "schema": { - "title": "Cluster Id", + "type": "integer", "minimum": 0, - "type": "integer" + "title": "Cluster Id" }, "name": "cluster_id", "in": "query" @@ -1708,9 +1724,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1718,9 +1734,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1728,9 +1744,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -1846,9 +1862,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1856,9 +1872,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -1866,9 +1882,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -1985,9 +2001,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -1995,9 +2011,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -2005,9 +2021,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -2123,9 +2139,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -2133,9 +2149,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -2143,9 +2159,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -2262,9 +2278,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -2272,9 +2288,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -2282,9 +2298,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -2398,9 +2414,9 @@ { "required": true, "schema": { - "title": "Solver Key", + "type": "string", "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", - "type": "string" + "title": "Solver Key" }, "name": "solver_key", "in": "path" @@ -2408,9 +2424,9 @@ { "required": true, "schema": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "name": "version", "in": "path" @@ -2418,9 +2434,9 @@ { "required": true, "schema": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "name": "job_id", "in": "path" @@ -2519,174 +2535,174 @@ "components": { "schemas": { "Body_upload_file_v0_files_content_put": { - "title": "Body_upload_file_v0_files_content_put", - "required": [ - "file" - ], - "type": "object", "properties": { "file": { - "title": "File", "type": "string", - "format": "binary" + "format": "binary", + "title": "File" } - } - }, - "ErrorGet": { - "title": "ErrorGet", + }, + "type": "object", "required": [ - "errors" + "file" ], - "type": "object", + "title": "Body_upload_file_v0_files_content_put" + }, + "ErrorGet": { "properties": { "errors": { - "title": "Errors", + "items": {}, "type": "array", - "items": {} + "title": "Errors" } - } - }, - "File": { - "title": "File", + }, + "type": "object", "required": [ - "id", - "filename" + "errors" ], - "type": "object", + "title": "ErrorGet" + }, + "File": { "properties": { "id": { - "title": "Id", "type": "string", - "description": "Resource identifier", - "format": "uuid" + "format": "uuid", + "title": "Id", + "description": "Resource identifier" }, "filename": { - "title": "Filename", "type": "string", + "title": "Filename", "description": "Name of the file with extension" }, "content_type": { - "title": "Content Type", "type": "string", + "title": "Content Type", "description": "Guess of type content [EXPERIMENTAL]" }, "checksum": { - "title": "Checksum", - "pattern": "^[a-fA-F0-9]{64}$", "type": "string", + "pattern": "^[a-fA-F0-9]{64}$", + "title": "Checksum", "description": "SHA256 hash of the file's content" }, "e_tag": { - "title": "E Tag", "type": "string", + "title": "E Tag", "description": "S3 entity tag" } }, + "type": "object", + "required": [ + "id", + "filename" + ], + "title": "File", "description": "Represents a file stored on the server side i.e. a unique reference to a file in the cloud." }, "Groups": { - "title": "Groups", - "required": [ - "me", - "all" - ], - "type": "object", "properties": { "me": { "$ref": "#/components/schemas/UsersGroup" }, "organizations": { - "title": "Organizations", - "type": "array", "items": { "$ref": "#/components/schemas/UsersGroup" }, + "type": "array", + "title": "Organizations", "default": [] }, "all": { "$ref": "#/components/schemas/UsersGroup" } - } + }, + "type": "object", + "required": [ + "me", + "all" + ], + "title": "Groups" }, "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", "properties": { "errors": { - "title": "Validation errors", - "type": "array", "items": { "$ref": "#/components/schemas/ValidationError" - } + }, + "type": "array", + "title": "Validation errors" } - } + }, + "type": "object", + "title": "HTTPValidationError" }, "Job": { - "title": "Job", - "required": [ - "id", - "name", - "inputs_checksum", - "created_at", - "runner_name", - "url", - "runner_url", - "outputs_url" - ], - "type": "object", "properties": { "id": { - "title": "Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Id" }, "name": { - "title": "Name", + "type": "string", "pattern": "^([^\\s/]+/?){1,10}$", - "type": "string" + "title": "Name" }, "inputs_checksum": { - "title": "Inputs Checksum", "type": "string", + "title": "Inputs Checksum", "description": "Input's checksum" }, "created_at": { - "title": "Created At", "type": "string", - "description": "Job creation timestamp", - "format": "date-time" + "format": "date-time", + "title": "Created At", + "description": "Job creation timestamp" }, "runner_name": { - "title": "Runner Name", - "pattern": "^([^\\s/]+/?){1,10}$", "type": "string", + "pattern": "^([^\\s/]+/?){1,10}$", + "title": "Runner Name", "description": "Runner that executes job" }, "url": { - "title": "Url", + "type": "string", "maxLength": 2083, "minLength": 1, - "type": "string", - "description": "Link to get this resource (self)", - "format": "uri" + "format": "uri", + "title": "Url", + "description": "Link to get this resource (self)" }, "runner_url": { - "title": "Runner Url", + "type": "string", "maxLength": 2083, "minLength": 1, - "type": "string", - "description": "Link to the solver's job (parent collection)", - "format": "uri" + "format": "uri", + "title": "Runner Url", + "description": "Link to the solver's job (parent collection)" }, "outputs_url": { - "title": "Outputs Url", + "type": "string", "maxLength": 2083, "minLength": 1, - "type": "string", - "description": "Link to the job outputs (sub-collection)", - "format": "uri" + "format": "uri", + "title": "Outputs Url", + "description": "Link to the job outputs (sub-collection)" } }, + "type": "object", + "required": [ + "id", + "name", + "inputs_checksum", + "created_at", + "runner_name", + "url", + "runner_url", + "outputs_url" + ], + "title": "Job", "example": { "id": "f622946d-fd29-35b9-a193-abdd1095167c", "name": "solvers/isolve/releases/1.3.4/jobs/f622946d-fd29-35b9-a193-abdd1095167c", @@ -2699,15 +2715,8 @@ } }, "JobInputs": { - "title": "JobInputs", - "required": [ - "values" - ], - "type": "object", "properties": { "values": { - "title": "Values", - "type": "object", "additionalProperties": { "anyOf": [ { @@ -2726,13 +2735,20 @@ "type": "string" }, { - "type": "array", - "items": {} + "items": {}, + "type": "array" } ] - } + }, + "type": "object", + "title": "Values" } }, + "type": "object", + "required": [ + "values" + ], + "title": "JobInputs", "example": { "values": { "x": 4.33, @@ -2747,22 +2763,14 @@ } }, "JobOutputs": { - "title": "JobOutputs", - "required": [ - "job_id", - "results" - ], - "type": "object", "properties": { "job_id": { - "title": "Job Id", "type": "string", - "description": "Job that produced this output", - "format": "uuid" + "format": "uuid", + "title": "Job Id", + "description": "Job that produced this output" }, "results": { - "title": "Results", - "type": "object", "additionalProperties": { "anyOf": [ { @@ -2781,13 +2789,21 @@ "type": "string" }, { - "type": "array", - "items": {} + "items": {}, + "type": "array" } ] - } + }, + "type": "object", + "title": "Results" } }, + "type": "object", + "required": [ + "job_id", + "results" + ], + "title": "JobOutputs", "example": { "job_id": "99d9ac65-9f10-4e2f-a433-b5e412bb037b", "results": { @@ -2803,48 +2819,48 @@ } }, "JobStatus": { - "title": "JobStatus", - "required": [ - "job_id", - "state", - "submitted_at" - ], - "type": "object", "properties": { "job_id": { - "title": "Job Id", "type": "string", - "format": "uuid" + "format": "uuid", + "title": "Job Id" }, "state": { "$ref": "#/components/schemas/RunningState" }, "progress": { - "title": "Progress", + "type": "integer", "maximum": 100, "minimum": 0, - "type": "integer", + "title": "Progress", "default": 0 }, "submitted_at": { - "title": "Submitted At", "type": "string", - "description": "Last modification timestamp of the solver job", - "format": "date-time" + "format": "date-time", + "title": "Submitted At", + "description": "Last modification timestamp of the solver job" }, "started_at": { - "title": "Started At", "type": "string", - "description": "Timestamp that indicate the moment the solver starts execution or None if the event did not occur", - "format": "date-time" + "format": "date-time", + "title": "Started At", + "description": "Timestamp that indicate the moment the solver starts execution or None if the event did not occur" }, "stopped_at": { - "title": "Stopped At", "type": "string", - "description": "Timestamp at which the solver finished or killed execution or None if the event did not occur", - "format": "date-time" + "format": "date-time", + "title": "Stopped At", + "description": "Timestamp at which the solver finished or killed execution or None if the event did not occur" } }, + "type": "object", + "required": [ + "job_id", + "state", + "submitted_at" + ], + "title": "JobStatus", "example": { "job_id": "145beae4-a3a8-4fde-adbb-4e8257c2c083", "state": "STARTED", @@ -2854,48 +2870,48 @@ } }, "Meta": { - "title": "Meta", - "required": [ - "name", - "version", - "docs_url", - "docs_dev_url" - ], - "type": "object", "properties": { "name": { - "title": "Name", - "type": "string" + "type": "string", + "title": "Name" }, "version": { - "title": "Version", + "type": "string", "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "title": "Version" }, "released": { - "title": "Released", - "type": "object", "additionalProperties": { - "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", - "type": "string" + "type": "string", + "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$" }, + "type": "object", + "title": "Released", "description": "Maps every route's path tag with a released version" }, "docs_url": { - "title": "Docs Url", + "type": "string", "maxLength": 65536, "minLength": 1, - "type": "string", - "format": "uri" + "format": "uri", + "title": "Docs Url" }, "docs_dev_url": { - "title": "Docs Dev Url", + "type": "string", "maxLength": 65536, "minLength": 1, - "type": "string", - "format": "uri" + "format": "uri", + "title": "Docs Dev Url" } }, + "type": "object", + "required": [ + "name", + "version", + "docs_url", + "docs_dev_url" + ], + "title": "Meta", "example": { "name": "simcore_service_foo", "version": "2.4.45", @@ -2908,58 +2924,51 @@ } }, "OnePage_SolverPort_": { - "title": "OnePage[SolverPort]", - "required": [ - "items" - ], - "type": "object", "properties": { "items": { - "title": "Items", - "type": "array", "items": { "$ref": "#/components/schemas/SolverPort" - } + }, + "type": "array", + "title": "Items" }, "total": { - "title": "Total", + "type": "integer", "minimum": 0, - "type": "integer" + "title": "Total" } }, + "type": "object", + "required": [ + "items" + ], + "title": "OnePage[SolverPort]", "description": "A single page is used to envelope a small sequence that does not require\npagination\n\nIf total > MAXIMUM_NUMBER_OF_ITEMS_PER_PAGE, we should consider extending this\nentrypoint to proper pagination" }, "Profile": { - "title": "Profile", - "required": [ - "id", - "login", - "role" - ], - "type": "object", "properties": { "first_name": { - "title": "First Name", - "maxLength": 255, "type": "string", + "maxLength": 255, + "title": "First Name", "example": "James" }, "last_name": { - "title": "Last Name", - "maxLength": 255, "type": "string", + "maxLength": 255, + "title": "Last Name", "example": "Maxwell" }, "id": { - "title": "Id", - "exclusiveMinimum": true, "type": "integer", + "exclusiveMinimum": true, + "title": "Id", "minimum": 0 }, "login": { - "title": "Login", "type": "string", - "format": "email" + "format": "email", + "title": "Login" }, "role": { "$ref": "#/components/schemas/UserRoleEnum" @@ -2968,12 +2977,19 @@ "$ref": "#/components/schemas/Groups" }, "gravatar_id": { - "title": "Gravatar Id", - "maxLength": 40, "type": "string", + "maxLength": 40, + "title": "Gravatar Id", "description": "md5 hash value of email to retrieve an avatar image from https://www.gravatar.com" } }, + "type": "object", + "required": [ + "id", + "login", + "role" + ], + "title": "Profile", "example": { "id": "20", "first_name": "James", @@ -2997,25 +3013,25 @@ } }, "ProfileUpdate": { - "title": "ProfileUpdate", - "type": "object", "properties": { "first_name": { - "title": "First Name", - "maxLength": 255, "type": "string", + "maxLength": 255, + "title": "First Name", "example": "James" }, "last_name": { - "title": "Last Name", - "maxLength": 255, "type": "string", + "maxLength": 255, + "title": "Last Name", "example": "Maxwell" } - } + }, + "type": "object", + "title": "ProfileUpdate" }, "RunningState": { - "title": "RunningState", + "type": "string", "enum": [ "UNKNOWN", "PUBLISHED", @@ -3028,54 +3044,54 @@ "ABORTED", "WAITING_FOR_CLUSTER" ], - "type": "string", + "title": "RunningState", "description": "State of execution of a project's computational workflow\n\nSEE StateType for task state" }, "Solver": { - "title": "Solver", - "required": [ - "id", - "version", - "title", - "maintainer", - "url" - ], - "type": "object", "properties": { "id": { - "title": "Id", - "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", "type": "string", + "pattern": "^simcore/services/comp/([a-z0-9][a-z0-9_.-]*/)*([a-z0-9-_]+[a-z0-9])$", + "title": "Id", "description": "Solver identifier" }, "version": { - "title": "Version", - "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", "type": "string", + "pattern": "^(0|[1-9]\\d*)(\\.(0|[1-9]\\d*)){2}(-(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*)(\\.(0|[1-9]\\d*|\\d*[-a-zA-Z][-\\da-zA-Z]*))*)?(\\+[-\\da-zA-Z]+(\\.[-\\da-zA-Z-]+)*)?$", + "title": "Version", "description": "semantic version number of the node" }, "title": { - "title": "Title", "type": "string", + "title": "Title", "description": "Human readable name" }, "description": { - "title": "Description", - "type": "string" + "type": "string", + "title": "Description" }, "maintainer": { - "title": "Maintainer", - "type": "string" + "type": "string", + "title": "Maintainer" }, "url": { - "title": "Url", + "type": "string", "maxLength": 2083, "minLength": 1, - "type": "string", - "description": "Link to get this resource", - "format": "uri" + "format": "uri", + "title": "Url", + "description": "Link to get this resource" } }, + "type": "object", + "required": [ + "id", + "version", + "title", + "maintainer", + "url" + ], + "title": "Solver", "description": "A released solver with a specific version", "example": { "id": "simcore/services/comp/isolve", @@ -3087,33 +3103,33 @@ } }, "SolverPort": { - "title": "SolverPort", - "required": [ - "key", - "kind" - ], - "type": "object", "properties": { "key": { - "title": "Key name", - "pattern": "^[^_\\W0-9]\\w*$", "type": "string", + "pattern": "^[^_\\W0-9]\\w*$", + "title": "Key name", "description": "port identifier name" }, "kind": { - "title": "Kind", + "type": "string", "enum": [ "input", "output" ], - "type": "string" + "title": "Kind" }, "content_schema": { - "title": "Content Schema", "type": "object", + "title": "Content Schema", "description": "jsonschema for the port's value. SEE https://json-schema.org" } }, + "type": "object", + "required": [ + "key", + "kind" + ], + "title": "SolverPort", "example": { "key": "input_2", "kind": "input", @@ -3127,7 +3143,7 @@ } }, "UserRoleEnum": { - "title": "UserRoleEnum", + "type": "string", "enum": [ "ANONYMOUS", "GUEST", @@ -3136,43 +3152,34 @@ "PRODUCT_OWNER", "ADMIN" ], - "type": "string", + "title": "UserRoleEnum", "description": "An enumeration." }, "UsersGroup": { - "title": "UsersGroup", - "required": [ - "gid", - "label" - ], - "type": "object", "properties": { "gid": { - "title": "Gid", - "type": "string" + "type": "string", + "title": "Gid" }, "label": { - "title": "Label", - "type": "string" + "type": "string", + "title": "Label" }, "description": { - "title": "Description", - "type": "string" + "type": "string", + "title": "Description" } - } - }, - "ValidationError": { - "title": "ValidationError", + }, + "type": "object", "required": [ - "loc", - "msg", - "type" + "gid", + "label" ], - "type": "object", + "title": "UsersGroup" + }, + "ValidationError": { "properties": { "loc": { - "title": "Location", - "type": "array", "items": { "anyOf": [ { @@ -3182,17 +3189,26 @@ "type": "integer" } ] - } + }, + "type": "array", + "title": "Location" }, "msg": { - "title": "Message", - "type": "string" + "type": "string", + "title": "Message" }, "type": { - "title": "Error Type", - "type": "string" + "type": "string", + "title": "Error Type" } - } + }, + "type": "object", + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError" } }, "securitySchemes": { diff --git a/services/api-server/src/simcore_service_api_server/api/routes/files.py b/services/api-server/src/simcore_service_api_server/api/routes/files.py index 98cd63b4bf6..20ed3da96cf 100644 --- a/services/api-server/src/simcore_service_api_server/api/routes/files.py +++ b/services/api-server/src/simcore_service_api_server/api/routes/files.py @@ -413,7 +413,20 @@ async def complete_multipart_upload( @router.get( - "/{file_id}/content", response_class=RedirectResponse, responses=_FILE_STATUS_CODES + "/{file_id}/content", + response_class=RedirectResponse, + responses=_FILE_STATUS_CODES + | { + 200: { + "content": { + "application/octet-stream": { + "schema": {"type": "string", "format": "binary"} + }, + "text/plain": {"schema": {"type": "string"}}, + }, + "description": "Returns a arbitrary binary data", + }, + }, ) async def download_file( file_id: UUID, diff --git a/services/api-server/tests/unit/conftest.py b/services/api-server/tests/unit/conftest.py index f9a947208de..28dd2e7e9cf 100644 --- a/services/api-server/tests/unit/conftest.py +++ b/services/api-server/tests/unit/conftest.py @@ -4,6 +4,8 @@ # pylint: disable=unused-variable import json +import os +import subprocess from collections.abc import AsyncIterator, Callable, Iterator from copy import deepcopy from pathlib import Path @@ -594,3 +596,15 @@ def _side_effect(self, request: httpx.Request, **kwargs): return respx_mock return _generate_mock + + +@pytest.fixture +def openapi_dev_specs(project_slug_dir: Path) -> dict[str, Any]: + openapi_file = (project_slug_dir / "openapi-dev.json").resolve() + if openapi_file.is_file(): + os.remove(openapi_file) + subprocess.run( + "make openapi-dev.json", cwd=project_slug_dir, shell=True, check=True + ) + assert openapi_file.is_file() + return json.loads(openapi_file.read_text()) diff --git a/services/api-server/tests/unit/test_api_files.py b/services/api-server/tests/unit/test_api_files.py index b1069c606bf..319c733e3b7 100644 --- a/services/api-server/tests/unit/test_api_files.py +++ b/services/api-server/tests/unit/test_api_files.py @@ -347,3 +347,11 @@ def side_effect_callback( assert file.sha256_checksum == SHA256Str(query["sha256_checksum"]) if "file_id" in query: assert file.id == UUID(query["file_id"]) + + +async def test_download_file_openapi_specs(openapi_dev_specs: dict[str, Any]): + """Test that openapi-specs for download file entrypoint specifies a binary file is returned in case of return status 200""" + file_download_responses: dict[str, Any] = openapi_dev_specs["paths"][ + f"/{API_VTAG}/files/{{file_id}}/content" + ]["get"]["responses"] + assert "application/octet-stream" in file_download_responses["200"]["content"]