You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用jq筛选OpenAPI/Swagger JSON中标记为public的接口方法

解决OpenAPI规范中保留public方法的jq过滤问题

问题描述

我是jq新手,搞不定符合需求的过滤器,求助:我有一份OpenAPI 3.0(或Swagger 2.0)的规范文件,其中paths元素包含多个endpoint,每个endpoint下有get、post等方法。我需要一个jq过滤器,仅保留标记有"x-visibility": "public"的方法,移除其他方法。我尝试过以下命令:

.paths |= map(select(.[]."x-visibility" == "public" | not))

但显然无法正常工作。以下是简化后的OpenAPI 3.0规范示例:

{"openapi": "3.0.1","info": {"title": "API service","description": "Exposing useful methods","x-descriptionForPublicDocs": "This is a test description for public docs specifically","contact": {"name": "Message me","url": "https://message.me"},"version": "1.0"},"servers": [{"url": "http://localhost:9090","description": "Generated server url"}],"tags": [{"name": "AccountGroups"}],"x-tags": [{"name": "TestResourceLists"}],"paths": {"/crane/v1/resource_list/{id}": {"get": {"tags": ["ResourceLists"],"x-tags": "TestResourceLists","x-visibility": "public","summary": "Get Resource List by ID","description": "Returns the resource list that has the specified ID.","operationId": "getById","parameters": [{"name": "id","in": "path","description": "ResourceList Id","required": true,"schema": {"type": "string"}}],"responses": {"200": {"description": "Successful operation","content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/ResourceListModel"}}}},"400": {"description": "Bad Request","content": {"*/*": {"schema": {"type": "object"}}}},"403": {"description": "Forbidden","content": {"*/*": {"schema": {"type": "object"}}}},"500": {"description": "Internal Server Error","content": {"*/*": {"schema": {"type": "object"}}}},"4XX": {"description": "Client error","content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/SpringErrorResponse"}}}}}},"put": {"tags": ["ResourceLists"],"x-visibility": "internal","summary": "Update Resource List","description": "Updates the resource list that has the specified ID.","operationId": "update","parameters": [{"name": "id","in": "path","description": "ResourceList Id","required": true,"schema": {"type": "string"}}],"requestBody": {"description": "Model for Resource List","content": {"application/json": {"schema": {"$ref": "#/components/schemas/ResourceListModel"}},"examples": {"TAG": {"description": "Tag ResourceList","value": {"members": [{"string": "string"}],"name": "string","resourceListType": "TAG","description": "string"}},"RESOURCE_GROUP": {"description": "RESOURCE_GROUP ResourceList","value": {"description": "string","members": ["string","string"],"name": "string","resourceListType": "RESOURCE_GROUP"}},"COMPUTE_ACCESS_GROUP": {"description": "COMPUTE_ACCESS_GROUP ResourceList","value": {"description": "string","members": [{"appIDs": ["*"],"clusters": ["*"],"codeRepos": ["*"],"containers": ["*"],"functions": ["*"],"hosts": ["*"],"images": ["*"],"labels": ["*"],"namespaces": ["*"]}],"name": "string","resourceListType": "COMPUTE_ACCESS_GROUP"}}}},"required": true},"responses": {"200": {"description": "Successful operation","content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/ResourceListModel"}}}},"400": {"description": "Bad Request","content": {"*/*": {"schema": {"type": "object"}}}},"403": {"description": "Forbidden","content": {"*/*": {"schema": {"type": "object"}}}},"500": {"description": "Internal Server Error","content": {"*/*": {"schema": {"type": "object"}}}},"4XX": {"description": "Client error","content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/SpringErrorResponse"}}}}}},"delete": {"tags": ["ResourceLists"],"x-visibility": "internal","summary": "Delete Resource List","description": "Deletes the resource list that has the specified ID.","operationId": "delete","parameters": [{"name": "id","in": "path","description": "ResourceList Id","required": true,"schema": {"type": "string"}}],"responses": {"204": {"description": "Successful operation"},"400": {"description": "Bad Request","content": {"*/*": {"schema": {"type": "object"}}}},"403": {"description": "Forbidden","content": {"*/*": {"schema": {"type": "object"}}}},"500": {"description": "Internal Server Error","content": {"*/*": {"schema": {"type": "object"}}}},"4XX": {"description": "Client error","content": {"*/*": {"schema": {"$ref": "#/components/schemas/SpringErrorResponse"}}}}}}},"/crane/v1/account_group/{id}": {"get": {"tags": ["AccountGroups"],"x-visibility": "public","summary": "Get resource","description": "Returns something","operationId": "getById_1","parameters": [{"name": "id","in": "path","description": "Account Group ID","required": true,"schema": {"type": "string"}},{"name": "includeAccountInfo","in": "query","description": "Include Cloud Account details","required": false,"schema": {"type": "boolean"}}],"responses": {"200": {"description": "Successful operation","content": {"application/json": {"schema": {"$ref": "#/components/schemas/AccountGroupModel"}}}},"400": {"description": "Bad Request","content": {"*/*": {"schema": {"type": "object"}}}},"403": {"description": "Forbidden","content": {"*/*": {"schema": {"type": "object"}}}},"500": {"description": "Internal Server Error","content": {"*/*": {"schema": {"type": "object"}}}},"4XX": {"description": "Client error","content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/SpringErrorResponse"}}}}}},"put": {"tags": ["AccountGroups"],"x-visibility": "internal","summary": "Update resource","description": "Update information","operationId": "update_1","parameters": [{"name": "id","in": "path","description": "AccountGroup Id","required": true,"schema": {"type": "string"}}],"requestBody": {"content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/AccountGroupModel"}}}},"required": true},"responses": {"200": {"description": "Successful operation"},"400": {"description": "Bad Request","content": {"*/*": {"schema": {"type": "object"}}}},"403": {"description": "Forbidden","content": {"*/*": {"schema": {"type": "object"}}}},"500": {"description": "Internal Server Error","content": {"*/*": {"schema": {"type": "object"}}}},"4XX": {"description": "Client error","content": {"application/json; charset=UTF-8": {"schema": {"$ref": "#/components/schemas/SpringErrorResponse"}}}}}},"delete": {"tags": ["AccountGroups"],"x-visibility": "internal","summary": "Delete resource","description": "Deletes the resource","operationId": "delete_1","parameters": [{"name": "id","in": "path","description": "Delete resource","required": true,"schema": {"type": "string"}}],"responses": {"200": {"description": "Successful operation"},"400": {"description": "Bad Request","content": {"*/*": {"schema": {"type": "object"}}}},"403": {"description": "Forbidden","content": {"*/*": {"schema": {"type": "object"}}}},"500": {"description": "Internal Server Error","content": {"*/*": {"schema": {"type": "object"}}}},"4XX": {"description": "Client error","content": {"*/*": {"schema": {"$ref": "#/components/schemas/SpringErrorResponse"}}}}}}}}}

解决方案

问题出在哪

你之前的命令用了map,但paths是对象不是数组,map只适用于数组;另外逻辑也搞反了,你要保留x-visibility为public的方法,结果写的是排除它们。

正确的jq过滤器

.paths |= with_entries(
  .value |= with_entries(
    select(.value."x-visibility" == "public")
  )
)

代码解释

  • with_entries:专门用来处理对象的键值对,比map适配paths这种结构
  • 第一层with_entries:遍历每个endpoint路径(比如/crane/v1/resource_list/{id})
  • 第二层with_entries:遍历每个endpoint下的HTTP方法(get/put/delete等)
  • select(.value."x-visibility" == "public"):只保留方法里x-visibility等于public的条目

进阶优化:移除空endpoint

如果某个endpoint下的所有方法都被过滤掉了,你可能想把这个空的endpoint也删掉,用下面的命令:

.paths |= with_entries(
  .value |= with_entries(
    select(.value."x-visibility" == "public")
  ) | select(length > 0)
)

内容的提问来源于stack exchange,提问作者3agpot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 03:05:33