用于访问Engee的外部编程接口
*Engee*为第三方应用程序的开发人员提供编程接口(HTTP API),允许第三方应用程序登录*Engee*并在*Engee*系统中代表用户执行操作。
要访问*Engee*HTTP API,必须代表用户授权第三方应用程序。 支持两种相等的授权方法:
-
使用标准OAuth2.0;
-
通过用户在*Engee*个人帐户中生成的个人访问令牌(PAT)。
在这两种情况下,与API的进一步交互都以相同的方式执行—使用标头。
授权:Bearer<token>.
通过OAuth2.0授权
OAuth用于需要交互式用户授权的情况(例如,集成web或桌面应用程序时)。
准备工作
第三方应用程序的开发人员将以下信息传输给*Engee*开发人员:
-
重定向_uri-授权后将用户重定向到的第三方应用程序中的URL。
开发者*Engee*传送给第三方应用程序的开发者:
-
客户端_id-应用程序ID; -
客户密码-应用程序的密钥; -
范围-允许的Api列表。
授权程序
-
第三方应用程序将用户重定向到
授权URL(https://engee.com/account/authorize) 具有以下查询参数:-
客户端_id—第三方应用程序的ID; -
重定向_uri-用户的返回URL; -
响应类型-回应类型(必须是密码); -
范围-授权Api; -
国家-来自第三方应用程序的任意数据。请求示例:
-
-
确认访问后,用户将被重定向到
重定向_uri带参数:-
密码-授权码; -
范围-授权Api; -
国家-在上一步中传递的值。例子::
-
-
要接收令牌,您必须发送
职位-要求令牌URL(https://engee.com/account/api/oauth2/token) 与身体应用程序/x-www-form-url编码:-
grant_type=authorization_code; -
密码-在上一步中获得的代码; -
客户端_id; -
客户密码; -
范围; -
重定向_uri.请求示例:
curl -d grant_type=authorization_code \ -d code=$code \ -d client_id=$client_id \ -d client_secret=$client_secret \ -d "scope=user:id user:username profile:name profile:primary_email engee" \ -d redirect_uri=$redirect_uri \ https://engee.com/account/api/oauth2/token
-
响应返回:
-
access_token-用于请求的授权; -
refresh_token-用于更新访问令牌。
| 访问令牌的生存期为10分钟,刷新令牌为30天。 |
通过个人访问令牌(PAT)进行授权
个人访问令牌(PAT)是为交互式场景而设计的 不需要用户授权(脚本、CI/CD、服务器集成)。
PAT由用户在*Engee*个人帐户中手动创建,然后使用 类似于通过OAuth获得的访问令牌。
拍拍
-
打开 Engee的个人帐户。
-
转到部分*通信和安全*→个人访问令牌。

-
单击*添加新令牌*。
-
指定:
-
令牌名称;
-
描述(可选);
-
有效期;
-
权限(例如,访问Engee API)。

-
-
单击*添加个人访问令牌*。
-
复制生成的令牌。

要复制,请使用按钮
,供浏览 —
.
|
创建后立即保存令牌。 无法在界面中重新查看。 |
与工程师的互动
为了使所有Api与*Engee*交互,系统必须由用户启动(在个人帐户中按下启动*Engee*按钮)。 如果无法按下开始按钮,那么您还可以自动执行*Engee*的启动和停止(请参阅下面对*Engee*控制方法的描述)。
必须将authorization标头"Authorization:Bearer$token"添加到所有请求中(该令牌是通过OAuth获得的或作为个人访问令牌创建的)。
API方法
所有管理Api的前缀*Engee* — https://engee.com.
工程师管理
获取/帐户/api/工程师/信息 -获取有关*Engee*状态的信息。 响应体:
{
"username": "string",
"serverName": "string",
"serverId": "string",
"url": "string",
"serverStatus": "starting"|"running"|"stopping"|"stopped",
"startingAt": "2025-02-10T10:24:31.328Z",
"startedAt": "2025-02-10T10:24:31.328Z",
"stoppingAt": "2025-02-10T10:24:31.328Z",
"stoppedAt": "2025-02-10T10:24:31.328Z",
"lastActivityAt": "2025-02-10T10:24:31.328Z",
"inactivityTimeout": 0,
"stopSessionAt": "2025-02-10T10:24:31.328Z",
"clusterNamespace": {
"minimalMode": true
}
}
邮递/帐户/api/工程师/开始 -启动*Engee*(类似于按个人帐户中的启动*Engee*按钮)。 响应正文(正在启动的服务器的URL):
{
'server': string
}
删除/帐户/api/引擎/停止 -停止*Engee*。 返回响应代码204。
所有其他Api的前缀具有以下形式: https://engee.com/prod/user/$许可证-nickname昵称/. 每个用户都有自己的前缀,必须从URL字段的*Engee*状态响应中获取。
|
任意代码的执行
POST/外部/命令/eval
-
最简单的请求。 请求:
{ "command": "3 + 5" }返回的数据:
-
状态码:200.
{ "result": "8" }
-
-
执行源代码时发生错误。 请求:
{ "command": "unexisting_variable" }返回的数据:
-
状态码:400.
{ "result_code": "command_error", "error": { "full_description": "UndefVarError: `unexisting_variable` not defined\n\nStacktrace:\n [1] top-level scope\n @ none:1\n [2] eval(m::Module, e::Any)\n @ Core ./boot.jl:370\n [3] top-level scope\n @ none:4\n [4] eval\n @ ./boot.jl:370 [inlined]\n [5] eval_mask_code(code::String)\n @ Main.Masks /app/IJulia/preload_cells/masks.jl:206\n [6] eval_mask_codes(mask_codes::Vector{Main.Masks.MaskCode})\n @ Main.Masks /app/IJulia/preload_cells/masks.jl:197\n [7] |>\n @ ./operators.jl:907 [inlined]\n [8] evaluate_mask_codes(mask_codes::Vector{Dict{String, String}})\n @ Main.Masks /app/IJulia/preload_cells/masks.jl:272\n [9] |>\n @ ./operators.jl:907 [inlined]\n [10] (::Workspaces.Servers.var\"#eval_mask_codes#157\"{typeof(Main.Masks.evaluate_mask_codes), Workspaces.Servers.var\"#convert_mask_result#156\"})(blocks::Vector{Dict{String, String}})\n @ Workspaces.Servers /usr/local/julia-1.9.3/packages/Workspaces/2XYbD/src/servers/handlers.jl:539\n [11] request_pipeline(req::HTTP.Messages.Request, log_func::var\"#13#14\"{String}, req_params_func::Function, log_response_func::Workspaces.Servers.var\"#mask_log_and_response#159\"{Workspaces.Servers.var\"#result_to_response#158\"}, pipeline_stages::Workspaces.Servers.PipelineStages)\n @ Workspaces.Servers /usr/local/julia-1.9.3/packages/Workspaces/2XYbD/src/servers/handlers_common.jl:282\n [12] required_body_request_pipeline\n @ /usr/local/julia-1.9.3/packages/Workspaces/2XYbD/src/servers/handlers_common.jl:289 [inlined]\n [13] eval_mask_code_handler\n @ /usr/local/julia-1.9.3/packages/Workspaces/2XYbD/src/servers/handlers.jl:556 [inlined]\n [14] (::Workspaces.Servers.var\"#eval_mask_code#186\"{var\"#13#14\"{String}, typeof(Main.Masks.evaluate_mask_codes)})(req::HTTP.Messages.Request)\n @ Workspaces.Servers /usr/local/julia-1.9.3/packages/Workspaces/2XYbD/src/servers/Servers.jl:68\n [15] (::HTTP.Handlers.Router{typeof(HTTP.Handlers.default404), typeof(HTTP.Handlers.default405), Nothing})(req::HTTP.Messages.Request)\n @ HTTP.Handlers /usr/local/julia-1.9.3/packages/HTTP/sJD5V/src/Handlers.jl:439\n [16] (::HTTP.Handlers.var\"#1#2\"{HTTP.Handlers.Router{typeof(HTTP.Handlers.default404), typeof(HTTP.Handlers.default405), Nothing}})(stream::HTTP.Streams.Stream{HTTP.Messages.Request, HTTP.Connections.Connection{Sockets.TCPSocket}})\n @ HTTP.Handlers /usr/local/julia-1.9.3/packages/HTTP/sJD5V/src/Handlers.jl:58\n [17] #invokelatest#2\n @ ./essentials.jl:819 [inlined]\n [18] invokelatest\n @ ./essentials.jl:816 [inlined]\n [19] handle_connection(f::Function, c::HTTP.Connections.Connection{Sockets.TCPSocket}, listener::HTTP.Servers.Listener{Nothing, Sockets.TCPServer}, readtimeout::Int64, access_log::Nothing)\n @ HTTP.Servers /usr/local/julia-1.9.3/packages/HTTP/sJD5V/src/Servers.jl:469\n [20] macro expansion\n @ /usr/local/julia-1.9.3/packages/HTTP/sJD5V/src/Servers.jl:401 [inlined]\n [21] (::HTTP.Servers.var\"#16#17\"{HTTP.Handlers.var\"#1#2\"{HTTP.Handlers.Router{typeof(HTTP.Handlers.default404), typeof(HTTP.Handlers.default405), Nothing}}, HTTP.Servers.Listener{Nothing, Sockets.TCPServer}, Set{HTTP.Connections.Connection}, Int64, Nothing, ReentrantLock, Base.Semaphore, HTTP.Connections.Connection{Sockets.TCPSocket}})()\n @ HTTP.Servers ./task.jl:514", "short_description": "UndefVarError(:unexisting_variable)", "type": "UndefVarError" } }这里:
-
错误。完整描述-错误的完整描述以及堆栈跟踪。 输出类似于错误输出到终端; -
错误。短描述-无堆栈跟踪的异常; -
错误。类型-错误类型。
-
-
-
JSON文件返回。 请求:
{ "command": "using JSON\nJSON.json(\"a\"=>1)" }返回的数据:
-
状态码:200.
{ "result": "{\"a\":1}" }
-
上传文件
发布/外部/文件/上传
请求以格式发送 多部分/表单-数据.
领域 路径 包含以下格式的JSON:
{
"sources": [
"/user/some_dir"
]
}
这里:
-
里面的每个元素
资料来源指示将上载文件的目录。; -
领域
upload_files包含需要上传的文件; -
字段数
upload_files它必须与传输的目录数量相匹配。
请求示例:
curl -X 'POST' \
'https://engee.com/prod/user/$license-$user/external/file/upload' \
-H 'Authorization: Bearer $access_token' \
-H 'Content-Type: multipart/form-data' \
-F 'paths={
"sources": [
"/user/some_directory"
]
}' \
-F 'upload_files=@2.png;type=image/png'
-
如果上传文件的目录不存在,则会创建它。;
-
所有下载的文件必须位于目录内。
/用户否则,将返回错误403; -
如果该文件已经存在,则会在其名称中添加后缀。;
-
文件只有在完全下载后才会写入磁盘。 如果下载中断,文件将不会出现在文件系统中。
异步代码执行
要执行执行时间可能超过HTTP连接超时的代码,请使用异步API。 这种方法避免了在执行长期操作时断开连接。
|
同步和异步执行之间的选择:
|
创建后台任务
职位/外部/命令/职位/创建
在后台启动代码执行。 服务器接受任务并立即返回响应,而无需等待代码执行完成。
请求主体(application/json):
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"job_type": "EVAL",
"code": "a = 5; sleep(60); a * 2",
"name": "Мой расчет"
}
参数:
-
工作_id--唯一任务标识符(UUID)。 -
作业类型--任务类型("EVAL"). -
密码--要执行的代码。 -
姓名--可选任务名称,便于识别。
答案:
-
202已接受--任务已成功创建并排队等待执行。 -
409冲突--指定的任务工作_id它已经存在。如果您发送一个现有的请求 工作_id,然后系统会返回状态409冲突它不会创建任务的副本。
检查进度状态
获取/外部/命令/作业/{job_id}/结果
允许您获取任务的当前状态及其结果(当任务完成时)。
回答:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Мой расчет",
"job_type": "EVAL",
"status": "IN_PROGRESS",
"start_time": "2024-05-20T12:00:00Z",
"end_time": null,
"result": null
}
响应字段:
-
状况--完成情况:"IN_PROGRESS"(进行中)或"完成"(完成)。 -
开始时间--任务的开始时间。 -
结束时间--任务完成时间(填写时状态="完成"). -
结果--包含执行结果或错误(填写时状态="完成").
成功完成后的结果格式:
{
"type": "success",
"data": {
"text": "10"
}
}
执行错误时的结果格式:
{
"type": "error",
"data": {
"type": "UndefVarError",
"short_description": "UndefVarError(:some_variable)",
"full_description": "UndefVarError: `some_variable` not defined\n\nStacktrace:\n..."
}
}
答案:
-
200好--已收到有关任务的信息。 -
404未找到--指定的任务工作_id没有找到。
获取问题列表
获取/外部/命令/作业/列表
检索用户创建的所有任务的列表。
回答:
{
"jobs": [
{
"job_id": "16763be4-6022-406e-a950-fcd5018633ca",
"name": "task_1",
"job_type": "EVAL",
"status": "DONE",
"start_time": "2024-05-20T12:00:00Z",
"end_time": "2024-05-20T12:05:00Z",
"result": {
"type": "success",
"data": {
"text": "Результат выполнения..."
}
}
}
]
}
响应包含具有单个字段的对象 工作机会 --一系列任务。 将为每个任务返回完整信息,包括:
-
唯一标识符(
工作_id). -
完成情况(
状况). -
开始和结束时间戳。
-
执行的结果(如果任务完成)。