Para 1.57.0 常用 CLI 命令与 API 实测详解

Para 1.57.0 命令行工具 para-cli 全部子命令实测详解与 REST API curl 实测:setup 认证、JWT 换发、对象 CRUD、搜索分页过滤、应用管理、401/400/404 错误码对照与排障实录。

ParaJavaBaaS全文检索自托管REST API2026/10/24

Para 1.57.0 常用 CLI 命令与 API 实测详解

目标:系统梳理 Para 1.57.0 的两套操作入口——官方命令行工具 para-cli 的全部子命令与参数,以及 REST API 的认证与核心端点——所有命令与回显均在一台 Ubuntu 24.04 服务器(主机名 para-server,Para 1.57.0 监听 8080)上逐条实测,读者按本文命令可直接复现。

一、环境信息

本章列出实测环境,文中所有命令与回显均基于下表执行。

项目值
操作系统Ubuntu 24.04.3 LTS(主机名 para-server)
Para 服务端1.57.0,JAR 方式部署于 /opt/para,监听 http://localhost:8080(安装过程见 《Ubuntu 24.04 安装 Para 1.57.0 指南》)
para-cli1.24.9(npm 全局安装)
Node.jsv22.23.4(para-cli 的运行时)
curl系统自带 /usr/bin/curl
根应用凭据accessKey 为 app:para,secretKey 由服务端首次启动自动生成于 /opt/para/para-application.conf
实测日期2026-10-24

💡 说明:Para 的 CLI 与 API 操作都围绕「应用(app)」展开——每个应用有独立的 accessKey/secretKey 与数据空间;本文在根应用 app:para 下实测,另创建过子应用 myapp、tempapp 用于演示(后者演示完已删除)。

二、工具概览

2.1 两套操作入口与分工

Para 1.57.0 提供两套操作入口,定位不同:

入口形态适用场景
para-cliNode.js 命令行工具,凭据保存在本地 config.json服务器上的日常管理:批量导入文件、导出备份、索引重建、应用管理
REST APIHTTP + JSON,签名或 JWT 认证应用后端集成:程序内 CRUD、搜索、多语言客户端

分工建议:运维与数据搬运走 para-cli(文件即对象、交互友好),业务代码走 REST API。两者操作同一份数据,本文 4.x 与 5.x 的示例相互对应。

2.2 安装 para-cli

para-cli 是 npm 包,安装方式有两种(官方 README 给出):

# 方式一:全局安装
npm install -g para-cli
# 方式二:不经安装直接运行
npx para-cli

本文实测为全局安装方式,安装后确认版本:

para-cli --version

实测回显:

1.24.9

para-cli 依赖 Node.js 运行时,实测环境为 Node.js v22.23.4(node --version 回显)。

2.3 命令与参数总表(help 实测)

para-cli --help 输出全部子命令与选项,实测回显(全量照抄):

  Command-line tool for Para backend servers

  Usage:
    $ para-cli [command] [file]

  Commands:
    setup                                  Initial setup, prompts you to enter your Para API keys and endpoint
    apps                                   Returns a list of all Para apps
    types                                  Returns an object containing all currently defined data types in Para
    select <appid>                         Selects a Para app as a target for all subsequent read/write requests
    endpoints [add|remove]                 List and select Para server endpoints, add new or remove an exiting one
    create <file|glob> [--id] [--type]     Persists files as Para objects and makes them searchable
    read --id 123 [--id 345 ...]           Fetches objects with the given ids
    update <file.json|glob> ...            Updates Para objects with the data from a JSON file (must contain id field)
    delete [glob] --id 123 ...             Deletes one or more objects from Para
    search "query" [--limit --page --sort] Searches the Para index for objects given a query string
    rebuild-index                          Rebuilds the entire search index
    app-settings                           Returns all settings for the authenticated app
    new-key                                Generates a new secret key and saves it to config.json
    new-jwt                                Generates a new JWT super token to be used for app authentication (use --print for console output)
    new-app <name> --name --shared         Creates a new Para app (only works if you have the keys for the "root" app)
    delete-app <id>                        Deletes an existing Para app (only works for child apps, not the "root" app)
    export                                 Exports all data from the app's table
    import <file>                          Imports data from a previously exported ZIP archive
    ping                                   Tests the connection to the Para server
    me                                     Returns the JSON for the currently authenticated user or app

  Options:
    --type          Sets the "type" field of an object
    --id            Sets the "id" field of an object
    --sanitize      Strips all symbols from input files
    --accessKey     Sets the Para access key
    --secretKey     Sets the Para secret key
    --endpoint      Sets the URL of the Para server
    --sort          Sets the field on which to sort search results
    --desc          Descending sort for search results (default: true)
    --page          Page number for search results, "all" will auto-paginate through all results
    --limit         Limits the number of search results
    --lastKey       Sets the last id for search-after pagination
    --cwd           Sets the current directory - used for resolving file paths
    --encodeId      By default all ids are Base64 encoded, unless this is set to 'false'
    --help          Prints the list of commands
    --version       Prints the version of the program

  Examples:
    $ para-cli setup
    $ para-cli create my-blog-post.md
    $ para-cli read --id my-blog-post.md
    $ para-cli create index.html --type webpage --id "My new article" --sanitize
    $ para-cli delete --id 123 --id "my-blog-post.md"
    $ para-cli search "type:article AND title:*" --sort timestamp --desc false --limit 10
    $ para-cli search "*" --type article --page all
    $ para-cli new-key
    $ para-cli new-app "mynewapp" --name "Full app name"
    $ para-cli new-jwt --print
    $ para-cli apps
    $ para-cli types
    $ para-cli select scoold
    $ para-cli endpoints

总表解读:命令分五组——连接与身份(setup/ping/me/endpoints)、应用管理(apps/select/new-app/delete-app/app-settings)、对象读写(create/read/update/delete/search/types)、令牌与密钥(new-key/new-jwt)、数据搬运(export/import/rebuild-index)。--encodeId 默认 true(id 自动 Base64 编码)是后续 read/delete 实测行为的关键背景。

三、前置条件:认证配置

3.1 para-cli setup 配置凭据

para-cli 所有读写命令都需要凭据。首次使用运行 setup,按提示依次输入 accessKey、secretKey 与服务端地址:

para-cli setup

setup 为交互式向导:依次提示输入 Para access key、secret key 与 endpoint,输入 app:para、服务端自动生成的 secretKey、http://localhost:8080 后,凭据被保存到本地配置文件 ~/.config/para-cli-nodejs/config.json。配置结果可用无认证也能执行的 endpoints 命令交叉验证:

para-cli endpoints

实测回显(显示已配置的端点与 root 应用状态;提示选择时直接回车取消):

 ➤ 1. http://localhost:8080 ✔ root app configured
? Type the number of the Para endpoint to select:

Select endpoint cancelled.

3.2 凭据文件 config.json 与 JWT

查看配置文件内容:

cat /root/.config/para-cli-nodejs/config.json

实测回显(secretKey 为服务端生成的密钥,此处隐去,请勿外泄):

{
        "accessKey": "app:para",
        "secretKey": "(服务端自动生成的 Base64 密钥)",
        "endpoint": "http://localhost:8080",
        "selectedApp": {
                "accessKey": "app:myapp",
                "secretKey": "(myapp 的密钥,仅在选择子应用后存在)"
        },
        "jwt": "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTMzOTQ3OTksImlhdCI6MTc5Mjc4OTk5OSwibmJmIjoxNzkyNzg5OTk0LCJhcHBpZCI6ImFwcDpteWFwcCJ9.PR3JvLXGeqcS3t9xQRr0zUUORVzqQsr4pYS7Kb0dLOc"
}

结构说明:accessKey/secretKey 是根应用凭据;selectedApp 在执行 para-cli select <appid> 切换应用后出现,后续读写以它为准;jwt 是最近一次 new-jwt 生成的令牌缓存。若不想走交互式 setup,也可在每条命令后直接挂参数:para-cli --accessKey app:para --secretKey <密钥> --endpoint http://localhost:8080 <命令>。

四、para-cli 子命令详解

本章逐个演示核心子命令。实测均在 /opt/para 目录下执行(create 的文件路径为相对路径)。

4.1 连接与身份:ping / me / endpoints

ping——测试连通性与认证状态:

para-cli ping

实测回显:

✔ Connected to Para server v1.57.0 on http://localhost:8080. Authenticated as: app para (app:para)

me——返回当前认证主体的完整 JSON:

para-cli me

实测回显(输出节选,实测首尾):

{
  "id": "app:para",
  "type": "app",
  "name": "para",
  "stored": true,
  "indexed": true,
  "cached": true,
  "version": 0,
  "active": true,
  "appIdentifier": "para",
  "appid": "para",
  "datatypes": {
    "posts": "post",
    "objectses": "objects"
  },
  "objectURI": "/app/app%3Apara",
  "plural": "apps",
  "timestamp": 1792789694560,
  "tokenValiditySec": 86400
}

me 回显中的 datatypes 字段记录了该应用注册过的数据类型(此处 posts: post 是此前实测注册的)。

endpoints——多端点管理与选择,回显见 3.1 节:列出所有已配置端点(➤ 标记当前选中项,✔ root app configured 表示该端点已验证过 root 凭据),输入序号切换。

4.2 应用管理:apps / select / new-app / delete-app / app-settings

apps——列出服务器上全部应用:

para-cli apps

实测回显(此时服务器上有 3 个应用):

Found 3 apps on http://localhost:8080:
 [tempapp] [myapp] [para]

Typing para-cli select tempapp will switch to that app.
Current app: app:para

new-app——创建子应用(仅 root 应用凭据可执行):

para-cli new-app tempapp --name "Temp App"

实测回显:

✔ App created:
{
  "accessKey": "app:tempapp",
  "message": "Save these keys - they are shown only once!",
  "secretKey": "PA5jiFbHaumjDBociKvH/LQMMgkrC7izjVemFqGa3v9ANXUMyezXrA=="
}

⚠️ 注意:secretKey 只显示这一次,务必当场保存;丢失后无法找回,只能对该应用重新生成密钥。上面回显中的应用是实测时创建、演示删除后已销毁的临时应用,密钥已随之失效。

select——把后续读写切换到指定应用(输出包含在 apps 命令的提示里,Typing para-cli select tempapp will switch to that app):

para-cli select myapp

执行后 config.json 出现 selectedApp 段(见 3.2 节),后续 create/read/search 都作用于 myapp 的数据空间;切回根应用执行 para-cli select para。

delete-app——删除子应用(不能删 root 应用),交互式确认:

para-cli delete-app app:tempapp

实测回显:

? Are you sure you want to delete app:tempapp? ALL DATA FOR THAT APP WILL BE LOS
T! yes/No

交互终端中输入 yes 回车即执行删除。实测确认:未交互确认时(如管道输入)命令输出 Delete cancelled. 且应用列表保持不变——自动化脚本中删除应用请改用 REST API(见 5.5 节)。

app-settings——返回当前应用全部设置:

para-cli app-settings

实测回显(默认设置下为空对象):

{}

4.3 数据类型总表:types

types 返回 Para 内置的数据类型清单(复数名 → 单数类型名):

para-cli types

实测回显:

{
  "linkers": "linker",
  "addresses": "address",
  "sysprops": "sysprop",
  "webhooks": "webhook",
  "translations": "translation",
  "votes": "vote",
  "forms": "form",
  "users": "user",
  "apps": "app",
  "tags": "tag"
}

这份清单是 create 命令 --type 参数的合法取值参考(post、page 等自定义类型也可用,写入后同样出现在 search 结果中)。

4.4 对象写入:create

create 把本地文件持久化为 Para 对象并自动建立检索索引。先准备一个 Markdown 文件:

cat > hello-world.md << 'EOF'
---
title: Hello Para
tags: [demo]
---

My first Para object
EOF
para-cli create hello-world.md

实测回显:

✔ Creating hello-world
✔ Created 1 objects with a total size of 0 KB.
✔ Created 1 objects.

带参数创建示例:指定 id 与类型(命令形式来自 help 示例清单,--id "My new article" 直接决定对象 id,--sanitize 清除文件中的特殊符号):

para-cli create index.html --type webpage --id "My new article" --sanitize

验证:create 成功后立即 search 该文件名(search 详解见 4.8 节):

para-cli search "name:hello-world"

实测回显(输出节选,实测首尾):

[
  {
    "id": "aGVsbG8td29ybGQ=",
    "type": "post",
    "name": "hello-world",
    "stored": true,
    "indexed": true,
    "cached": true,
    "version": 0,
    "appid": "para",
    "creatorid": null,
    "objectURI": "/post/aGVsbG8td29ybGQ%3D",
    "parentid": null,
    "plural": "posts",
    "tags": [
      "demo"
    ],
    "timestamp": 1792789930344,
    "updated": null,
    "votes": 0,
    "title": "Hello Para",
    "content": "My first Para object"
  }
]

关键事实:id aGVsbG8td29ybGQ= 正是 hello-world 的 Base64 编码——--encodeId 默认开启所致(总表 Options 段原文:By default all ids are Base64 encoded)。

4.5 对象读取:read

read 按 id 取回对象,--id 可重复传多个:

para-cli read --id plain-post

实测回显:

[
  {
    "id": "plain-post",
    "type": "post",
    "name": "plain-post",
    "stored": true,
    "indexed": true,
    "cached": true,
    "version": 0,
    "appid": "para",
    "creatorid": null,
    "objectURI": "/post/plain-post",
    "parentid": null,
    "plural": "posts",
    "tags": [
      "demo"
    ],
    "timestamp": 1792789982141,
    "updated": null,
    "votes": 0,
    "title": "Hello Para",
    "content": "My first Para object"
  }
]

读取不存在的 id 返回空数组:

para-cli read --id no-such-object

实测回显:

[]

⚠️ 注意:read 的 --id 值是「编码前」的原始 id,para-cli 内部自动做 Base64 处理;直接传 Base64 串(如 aGVsbG8td29ybGQ=)反而会因二次编码而读不到。

4.6 对象更新:update

update 依据 JSON 文件中的 id 字段更新对象(help 原文:must contain id field)。先写更新文件再执行:

cat > plain-post.json << 'EOF'
{
  "id": "plain-post",
  "title": "Hello Para v2",
  "content": "updated content",
  "tags": ["demo"]
}
EOF
para-cli update plain-post.json

实测回显:

✔ Updating plain-post
✔ Updated 1 files.

验证:重新 read 确认字段已变:

para-cli read --id plain-post

实测回显(输出节选,实测首尾):

[
  {
    "id": "plain-post",
    "type": "post",
    "name": "plain-post",
    "stored": true,
    "indexed": true,
    "cached": true,
    "version": 0,
    "appid": "para",
    "objectURI": "/post/plain-post",
    "plural": "posts",
    "tags": [
      "demo"
    ],
    "timestamp": 1792789982141,
    "updated": 1792789999121,
    "votes": 0,
    "title": "Hello Para v2",
    "content": "updated content"
  }
]

title/content 已更新,updated 时间戳从 null 变为更新时刻(1792789999121),timestamp(创建时间)不变。

4.7 对象删除:delete

delete 按 id 删除对象,支持一次多个:

para-cli delete --id hello-world

实测回显:

✔ Deleted objects " [ 'aGVsbG8td29ybGQ=' ] " from Para.

回显中括号内是被删除对象的 Base64 编码 id(与 4.4 节 search 看到的 id 一致)。验证:再 read 该对象应返回空数组:

para-cli read --id hello-world

实测回显:

[]

4.8 搜索:search

search 全文检索当前应用的索引,查询语法与分页参数是重点。搜索全部对象:

para-cli search "*"

实测回显(3 个对象:一个子应用、一个 post、根应用):

[
  {
    "id": "app:myapp",
    "type": "app",
    "name": "My App",
    "stored": true,
    "indexed": true,
    "cached": true,
    "version": 0,
    "active": true,
    "appIdentifier": "myapp",
    "appid": "para",
    "creatorid": null,
    "datatypes": {},
    "deleteOn": null,
    "objectCount": 0,
    "objectURI": "/app/app%3Amyapp",
    "parentid": null,
    "plural": "apps",
    "readOnly": false,
    "resourcePermissions": {},
    "sharingIndex": false,
    "sharingTable": false,
    "tags": null,
    "timestamp": 1792789919308,
    "tokenValiditySec": 86400,
    "updated": null,
    "validationConstraints": {},
    "votes": 0
  },
  {
    "id": "aGVsbG8td29ybGQ=",
    "type": "post",
    "name": "hello-world",
    "stored": true,
    "indexed": true,
    "cached": true,
    "version": 0,
    "appid": "para",
    "creatorid": null,
    "objectURI": "/post/aGVsbG8td29ybGQ%3D",
    "parentid": null,
    "plural": "posts",
    "tags": [
      "demo"
    ],
    "timestamp": 1792789930344,
    "updated": null,
    "votes": 0,
    "title": "Hello Para",
    "content": "My first Para object"
  },
  {
    "id": "app:para",
    "type": "app",
    "name": "para",
    "stored": true,
    "indexed": true,
    "cached": true,
    "version": 0,
    "active": true,
    "appIdentifier": "para",
    "appid": "para",
    "creatorid": null,
    "datatypes": {
      "posts": "post"
    },
    "deleteOn": null,
    "objectCount": 0,
    "objectURI": "/app/app%3Apara",
    "parentid": null,
    "plural": "apps",
    "readOnly": false,
    "resourcePermissions": {},
    "sharingIndex": false,
    "sharingTable": false,
    "tags": null,
    "timestamp": 1792789694560,
    "tokenValiditySec": 86400,
    "updated": 1792789930358,
    "validationConstraints": {},
    "votes": 0
  }
]

无匹配结果时返回空数组:

para-cli search "title:nonexistent"

实测回显:

[]

排序与限量组合(help 示例原文,参数默认值:--desc 默认 true 即默认降序):

para-cli search "type:post AND title:*" --sort timestamp --desc false --limit 10

💡 技术拓展:搜索查询串的写法不止一种。Para 检索底层是 Apache Lucene,常用查询语法对比——

语法示例含义
通配匹配*全部对象
字段精确/前缀name:hello-world字段等于(或按 Lucene 前缀规则匹配)
布尔组合type:post AND title:*AND/OR/NOT 组合条件
短语检索title:"Hello Para"引号内按短语整体匹配

本文实测以通配与字段匹配为主(*、name:、type:),复杂组合查询可按 Lucene 语法书写。查询语法的完整规则见官方文档 Search 章节与 《Para 1.57.0 介绍与选型指南》中的检索层说明。

4.9 令牌与密钥:new-jwt / new-key

new-jwt——为当前应用生成 JWT 超级令牌(供 REST API 认证用,--print 直接输出到控制台):

para-cli new-jwt --print

实测回显(myapp 的令牌,有效期 7 天):

eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTMzOTQ3OTksImlhdCI6MTc5Mjc4OTk5OSwibmJmIjoxNzkyNzg5OTk0LCJhcHBpZCI6ImFwcDpteWFwcCJ9.PR3JvLXGeqcS3t9xQRr0zUUORVzqQsr4pYS7Kb0dLOc

令牌本体是三段式 JWT:对中间段做 Base64 解码,实测载荷为 {"exp":1793394799,"iat":1792789999,"nbf":1792789994,"appid":"app:myapp"}——appid 标明令牌所属应用,exp - iat = 604800 秒即 7 天有效期。不传 --print 时令牌静默写入 config.json 的 jwt 字段(见 3.2 节)。

new-key——为当前应用重新生成 secretKey 并保存到 config.json(help 原文:Generates a new secret key and saves it to config.json)。该命令会使旧密钥立即失效,多客户端场景需同步更新所有使用方,故本文未在实际环境执行,读者使用前先确认影响面。

4.10 导出、导入与索引维护:export / import / rebuild-index

export——导出当前应用全部数据为 ZIP:

para-cli export

实测回显:

✔ Exported 0MB of data to file para_20261023_211541.zip

导出文件落在当前工作目录,文件名自动带时间戳(para_年月日_时分秒.zip)。

import——把先前导出的 ZIP 导回应用(实测把 export 产物导回):

para-cli import /tmp/import_test.zip

实测回显:

✔ Imported 3 object into app "para"

rebuild-index——重建整个检索索引(存储与索引不一致时使用):

para-cli rebuild-index

实测回显:

{
  "tookMillis": 23,
  "reindexed": 3
}

五、REST API 实测详解

para-cli 的每个操作都有对应的 REST 端点;程序集成时直接调 REST API。本章全部用 curl 实测,端点前缀 http://localhost:8080。

5.1 认证方式总览与 JWT 获取

Para 服务端对受保护端点要求认证,可选方式如下:

方式机制适用
Sig4 签名请求按 AccessKey/SecretKey 计算 AWS 风格签名头(para-cli 内部即此方式)正式客户端库
JWT Bearer先用签名换发一次性 JWT,后续请求带 Authorization: Bearer <token>脚本与 curl 调试,最简便
免认证仅 para.security.ignored 列出的路径(/v1/_health、/v1/_config/options 等)健康检查、监控探测

本文按 JWT Bearer 路线实测。第一步用 para-cli 换发 root 应用令牌(内部走 Sig4 签名,无需手动算签名):

cd /opt/para
para-cli --accessKey app:para --secretKey "$(grep root_secret_key para-application.conf | cut -d'"' -f2)" new-jwt --print

实测回显(root 应用令牌):

eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTM0MTk4NjUsImlhdCI6MTc5MjgxNTA2NSwibmJmIjoxNzkyODE1MDYwLCJhcHBpZCI6ImFwcDpwYXJhIn0.xShf_nQVTaatHS01cTP4_S5JgwAPp_wuzDkpxUnuGQg

第二步存入 shell 变量供后续所有 curl 复用(取值来自上一步输出):

JWT="eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3OTM0MTk4NjUsImlhdCI6MTc5MjgxNTA2NSwibmJmIjoxNzkyODE1MDYwLCJhcHBpZCI6ImFwcDpwYXJhIn0.xShf_nQVTaatHS01cTP4_S5JgwAPp_wuzDkpxUnuGQg"

不认证直接访问受保护端点的实测结果见 5.6 节(401)。

5.2 免认证端点:_health 与 _config/options

健康检查(监控探测直接用):

curl -s http://localhost:8080/v1/_health

实测回显:

{"message":"healthy"}

配置选项(返回服务端全部配置项的元信息):

curl -s http://localhost:8080/v1/_config/options

实测回显(输出节选,实测首尾):

{"Core":{"para.app_name":{"defaultValue":"para","description":"The formal name of the web application.","type":"String","tags":""},"para.root_secret_override":{"defaultValue":"","description":"Overrides the secret key for the root Para app `app:para` once, upon first initialization.","type":"String"

该端点返回按模块(Core/Security 等)组织的配置项字典,含每个键的 defaultValue/description/type——排查配置问题时比翻文档更快,参数逐键详解见 《Para 1.57.0 配置参数详解》。

5.3 对象 CRUD

创建:POST /v1/objects。注意实测行为——该端点创建的对象使用默认类型:

curl -s -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"type":"post","title":"API Test","content":"created via REST API","tags":["demo"]}' \
  http://localhost:8080/v1/objects

实测回显:

{"id":"2024718385085943808","appid":"para","cached":true,"creatorid":null,"indexed":true,"name":"ParaObject 1792815065096","objectURI":"/objects/2024718385085943808","parentid":null,"plural":"objectses","stored":true,"tags":["demo"],"timestamp":1792815065145,"type":"objects","updated":null,"version":0,"votes":0,"title":"API Test","content":"created via REST API"}

回显关键点:即使请求体写了 "type":"post",POST /v1/objects 创建的对象 type 仍是默认的 objects(plural 为 objectses),id 由服务端生成(雪花 id 风格的长数字串)。要让对象落到指定类型,应 POST 到复数类型端点:

curl -s -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"title":"Post via /v1/posts","content":"typed object","tags":["api"]}' \
  http://localhost:8080/v1/posts

实测回显:

{"id":"2024718511435157504","appid":"para","cached":true,"creatorid":null,"indexed":true,"name":"ParaObject 1792815095269","objectURI":"/post/2024718511435157504","parentid":null,"plural":"posts","stored":true,"tags":["api"],"timestamp":1792815095269,"type":"post","updated":null,"version":0,"votes":0,"title":"Post via /v1/posts","content":"typed object"}

这次 type 正确落为 post、objectURI 为 /post/<id>。

读取:GET /v1/objects/{id}:

curl -s -H "Authorization: Bearer $JWT" http://localhost:8080/v1/objects/2024718385085943808

实测回显(与创建回显完全一致,逐字段相同):

{"id":"2024718385085943808","appid":"para","cached":true,"creatorid":null,"indexed":true,"name":"ParaObject 1792815065096","objectURI":"/objects/2024718385085943808","parentid":null,"plural":"objectses","stored":true,"tags":["demo"],"timestamp":1792815065145,"type":"objects","updated":null,"version":0,"votes":0,"title":"API Test","content":"created via REST API"}

更新:PATCH /v1/objects/{id},只传要改的字段:

curl -s -X PATCH -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \
  -d '{"title":"API Test v2"}' \
  http://localhost:8080/v1/objects/2024718385085943808

实测回显(输出节选,title 已更新、updated 时间戳出现):

{"id":"2024718385085943808","appid":"para","cached":true,"creatorid":null,"indexed":true,"name":"ParaObject 1792815065096","objectURI":"/objects/2024718385085943808","parentid":null,"plural":"objectses","stored":true,"tags":["demo"],"timestamp":1792815065145,"updated":1792815065358,"version":0,"votes":0,"title":"API Test v2","content":"created via REST API"}

删除:DELETE /v1/objects/{id},成功返回 200 与空响应体:

curl -s -o /dev/null -w "%{http_code}\n" -X DELETE -H "Authorization: Bearer $JWT" \
  http://localhost:8080/v1/posts/2024718511435157504

实测回显:

200

验证删除生效:再读已删除的对象,返回 404:

curl -s -w "\n%{http_code}\n" -H "Authorization: Bearer $JWT" \
  http://localhost:8080/v1/posts/2024718511435157504

实测回显:

{"code":404,"message":"Not Found"}
404

5.4 搜索、分页与过滤

搜索端点 GET /v1/search,q 为查询串。全量搜索:

curl -s -H "Authorization: Bearer $JWT" "http://localhost:8080/v1/search?q=*"

实测回显(输出节选,实测首尾;共 4 个命中:2 个 app 对象 + 2 个内容对象):

{"totalHits":4,"lastKey":"2024718511439351808","page":0,"items":[{"id":"app:para","active":true,"appIdentifier":"para","appid":"para","cached":true,"creatorid":null,"datatypes":{"posts":"post","objectses":"objects"},"deleteOn":null,"indexed":true,"name":"para","objectCount":0,"objectURI":"/app/app%3Apara","parentid":null,"plural":"apps","readOnly":false,"resourcePermissions":{},"sharingIndex":false,"sharingTable":false,"stored":true,"tags":null,"timestamp":1792789694560,"tokenValiditySec":86400,"type":"app","updated":1792789930358,"validationConstraints":{},"version":0,"votes":0},{"id":"app:myapp",...},{"id":"2024718385085943808",...},{"id":"plain-post",...}]}

响应结构说明:totalHits 是总命中数,page 是当前页号,items 是对象数组,lastKey 用于游标翻页(下一页请求带上 &lastKey=<lastKey 值>)。

类型过滤 + 限量(type 与 limit 参数组合):

curl -s -H "Authorization: Bearer $JWT" "http://localhost:8080/v1/search?q=*&type=post&limit=1"

实测回显:

{"totalHits":1,"lastKey":"2024613845670039554","page":0,"items":[{"id":"plain-post","appid":"para","cached":true,"creatorid":null,"indexed":true,"name":"plain-post","objectURI":"/post/plain-post","parentid":null,"plural":"posts","stored":true,"tags":["demo"],"timestamp":1792789982141,"type":"post","updated":1792789999121,"version":0,"votes":0,"title":"Hello Para v2","content":"updated content"}]}

type=post 过滤后只返回 post 对象,limit=1 限制每页条数——totalHits 也随之按过滤条件统计(此处为 1)。

非法查询串的报错(实测 Lucene 语法约束):

curl -s -H "Authorization: Bearer $JWT" "http://localhost:8080/v1/search?q=title:*"

实测回显:

{"code":400,"message":"Invalid query string syntax q=title:* in request GET /v1/search"}

单独的 字段:* 通配被服务端拒绝;组合条件(如 type:post AND title:*)或全量 * 可正常执行——这是 Lucene 查询解析层的限制,遇到 400 先调整查询串语法。

5.5 应用管理:GET /v1/apps 与 DELETE /v1/apps/{id}

应用列表(root 应用令牌可访问):

curl -s -H "Authorization: Bearer $JWT" http://localhost:8080/v1/apps

实测回显(输出节选,实测首尾;当时共 2 个应用):

{"totalHits":2,"lastKey":"2024718385736060928","page":0,"items":[{"id":"app:myapp","active":true,"appIdentifier":"myapp","appid":"para","cached":true,"creatorid":null,"datatypes":{"posts":"post"},"deleteOn":null,"indexed":true,"name":"My App","objectCount":0,"objectURI":"/app/app%3Amyapp","parentid":null,"plural":"apps","readOnly":false,"resourcePermissions":{},"sharingIndex":false,"sharingTable":false,"stored":true,"tags":null,"timestamp":1792789919308,"tokenValiditySec":86400,"type":"app","updated":1792790033405,"validationConstraints":{},"version":0,"votes":0},{"id":"app:para",...}]}

删除应用(DELETE /v1/apps/{accessKey},实测删除 tempapp,不可删除 root 应用):

curl -s -o /dev/null -w "%{http_code}\n" -X DELETE -H "Authorization: Bearer $JWT" \
  http://localhost:8080/v1/apps/app:tempapp

实测回显:

200

验证:再次 GET /v1/apps,totalHits 从 3 变为 2,tempapp 消失(实测回显省略,验证方法同上比对 totalHits)。这补上了 4.2 节 delete-app 交互确认无法自动化的缺口:自动化场景删应用走此 API。

5.6 错误响应实测:401 / 400 / 404

三类典型错误的实测回显,排障时可直接对照。

401 未认证——不带 Authorization 头访问受保护端点:

curl -s -w "\n%{http_code}\n" http://localhost:8080/v1/objects/aGVsbG8td29ybGQ=

实测回显:

{"code":401,"message":"You don't have permission to access this resource. [GET /v1/objects/aGVsbG8td29ybGQ=]"}
401

400 请求非法——查询串语法错误(完整实测回显见 5.4 节:{"code":400,"message":"Invalid query string syntax q=title:* in request GET /v1/search"})与空请求体触发 Jackson 解析错误均属此类。

404 资源不存在——读取已删除对象(见 5.3 节实测):

{"code":404,"message":"Not Found"}
404

排障对照:401 查凭据(令牌缺失/过期/应用错)、400 查请求体与查询串语法、404 查 id 是否存在与类型端点是否匹配(/v1/objects/{id} 与 /v1/posts/{id} 各自管各自的数据)。

六、注意事项

  1. secretKey 只显示一次:new-app 回显(4.2 节)明确提示 Save these keys - they are shown only once!,漏存只能换密钥重来;config.json 与 para-application.conf 是密钥的两个落盘点,注意文件权限,勿提交版本库。
  2. id 的 Base64 编码:para-cli 默认对 id 做 Base64 编解码(--encodeId 默认 true),命令参数里传原始 id;REST API 路径中的 id 同样可传原始值由服务端处理,但 delete 回显与 objectURI 中展示的是编码后的形式(4.4/4.7 节实测对照)。
  3. JWT 有效期:new-jwt 生成的令牌 7 天有效(实测载荷 exp-iat=604800 秒),过期后 401,重新生成即可;para-cli 内部会在调用时自动续期缓存到 config.json。
  4. 健康检查瞬时失败属正常:服务端日志偶见 Server is no longer healthy! Health check failed for services: Cache(实测 journalctl 记录,1 分钟后自动恢复 Server is healthy.),默认 CaffeineCache 的瞬时抖动,监控告警阈值建议放行单次失败。
  5. 交互式命令无法自动化:delete-app 的确认(4.2 节实测 Delete cancelled.)与 setup/endpoints 的选择提示都需要交互终端;脚本场景用 REST API 或直接挂 --accessKey/--secretKey 参数。

七、常见问题(FAQ)

Q1:para-cli read 返回 [],对象明明创建过?

两个最常见原因(均有实测对应):一是对象已被删除(4.7 节删除后 read 返回 []);二是 id 传错形态——para-cli 传原始 id 而非 Base64 编码值(4.5 节注意事项)。用 para-cli search "*" 先确认对象在不在、拿到原始 name 后再 read。

Q2:search 报 Invalid query string syntax(400)?

查询串不合法。实测 q=title:* 这种「单字段 + 纯通配」被服务端拒绝(5.4 节),改为全量 q=* 或组合条件 q=type:post AND title:* 即可。原则:* 单独用合法,跟在字段冒号后作为唯一条件会触发 Lucene 解析拒绝。

Q3:curl 调 API 全部返回 401?

认证头没带对。JWT 方式必须 Authorization: Bearer <token>(token 与 Bearer 之间一个空格);检查 token 是否属于目标应用(载荷 appid 字段)、是否过期(exp 字段)。快速自检:先用免认证端点 curl -s http://localhost:8080/v1/_health 确认服务本身正常,再排查认证(5.6 节 401 实测回显对照)。

Q4:POST /v1/objects 创建的对象 type 不对,怎么落成 post?

POST /v1/objects 固定创建默认类型 objects(5.3 节实测);指定类型要 POST 到复数端点 /v1/posts、/v1/pages 等(5.3 节实测 type 正确落为 post)。可用类型清单见 4.3 节 types 命令。

Q5:导出的 ZIP 导不回去或报数据异常?

import 只接受 export 产物(同版本导出的 ZIP,4.10 节实测导回 3 个对象)。跨版本迁移先升级两侧到同版本再导出导入;导出前用 para-cli apps 确认当前应用——export/import 只作用于当前选中应用的数据空间,别把 A 应用数据导进 B。

八、参考链接