关于 netbox-api-integration
面向编写 NetBox 集成的开发者,整理 REST 与 GraphQL API 的认证、查询、批量操作和性能实践,并涵盖版本差异与数据建模。
主要功能
- 01REST 与 GraphQL 查询实践
- 02令牌认证与版本注意事项
- 03分页和批量写入模式
- 04过滤、并发与性能优化
- 05NetBox 对象依赖与建模
适用场景
- 01编写 NetBox API 集成代码
- 02处理大型数据集的分页查询
- 03安全地批量创建或更新对象
MCP 相关
介绍在已配置 NetBox MCP server 或 NetBox Platform MCP 时,如何查询实时实例以核实字段、过滤器和对象状态。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ netboxlabs/ skills --skill netbox-api-integration安装后在 Claude Code 中输入/netbox-api-integration确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/authentication.mdbranching-patterns.mddata-modeling.mddiode-integration.mdgraphql-patterns.mdperformance.mdrest-api-patterns.md详细介绍
NetBox API 集成
与 NetBox REST 和 GraphQL API 集成的模式和实践。涵盖身份验证、查询、批量操作、性能优化、数据建模和集成工具。
目标版本: NetBox 4.5–4.7(当前版本:4.7.3)。v2 令牌需要 4.5+;REST 游标分页、ETag/If-Match 和 add_tags/remove_tags 需要 4.6+;?background=true、逐对象批量错误以及 {value, label} 选择型自定义字段从 4.7 开始支持。请参阅版本说明。
范围: 仅限 API 集成——不包括插件开发、自定义脚本或 NetBox 管理。
你对 NetBox API 的了解可能已经过时。 分页行为、筛选表达式、令牌格式和 GraphQL 功能会随版本变化。查询具体 API 细节时,优先检索,而非依赖预训练知识。
检索来源
| 来源 | URL / 方法 | 用途 |
|---|---|---|
| NetBox REST API 文档 | https://netboxlabs.com/docs/netbox/integrations/rest-api/ | 端点、筛选、分页 |
| NetBox GraphQL 文档 | https://netboxlabs.com/docs/netbox/integrations/graphql-api/ | 查询语法、架构 |
| pynetbox 仓库 | https://github.com/netbox-community/pynetbox | SDK 方法、变更日志 |
| NetBox MCP 服务 | 如已配置——查询实时实例,以验证对象架构和当前状态 | 字段名称、可用筛选条件、对象是否存在 |
| NetBox Platform MCP | 如已配置——针对实时 NetBox Cloud/Enterprise 进行完整 CRUD 验证 | 端到端验证 |
首先:验证连接
编写集成代码前,请确认 NetBox 实例可访问,且令牌有效:
curl -s -H "Authorization: Bearer $NETBOX_TOKEN" "$NETBOX_URL/api/status/" | python -m json.tool
你应会看到包含 netbox-version 的 JSON 响应。如果收到 403,说明令牌权限不足。如果连接被拒绝,请检查 URL。
身份验证
NetBox 4.5+ 使用 v2 令牌。v1 令牌自 4.6 起已弃用,并将在 5.0 中移除。
# v2 token (recommended)
headers = {"Authorization": "Bearer nbt_abc123.xxxxxxxxxxxxxxxx"}
# v1 token (legacy — deprecated 4.6, removed 5.0; migrate before 5.0)
headers = {"Authorization": "Token 0123456789abcdef01234567"}
v2 令牌要求在 NetBox 服务端配置中设置 API_TOKEN_PEPPERS。自动创建令牌时,请使用令牌配置端点(POST /api/users/tokens/provision/)。明文值位于创建/配置响应的 token 字段中(key 仅是公开标识符),且只返回一次(4.6.1+)——请立即保存;之后只会存储哈希值。
NetBox 4.7+: 创建时
token为只读字段——服务端始终生成明文值,并忽略客户端提供的值。切勿使用?background=true创建令牌:4.7.0/4.7.1 会将明文记录在作业结果中(任何拥有core.view_job权限的人都能读取);4.7.2 则会以 400 拒绝请求。请运行 ≥ 4.7.2,并轮换以此方式创建的任何令牌。现在,通过POST /api/extras/scripts/<id>/运行自定义脚本,需要使用启用了写入权限的令牌。
令牌迁移、IP 限制和配置详情,请参阅 references/authentication.md。
REST API 基础
始终进行分页
def get_all(api_url, endpoint, headers, limit=100):
results, url = [], f"{api_url}/{endpoint}/?limit={limit}"
while url:
data = requests.get(url, headers=headers).json()
results.extend(data["results"])
url = data.get("next")
return results
NetBox 4.6+——游标分页。 对于大型数据集,请传入
?start=<pk>&limit=<n>,而不是offset。此方式会返回id >= start的对象,并按 PK 排序。迭代时,将下一次请求的start设为最后一个结果的id+ 1;持续跟进next,直到其为 null。注意事项:同时使用start和offset→ 400;游标模式下count始终为null;previous始终为null(仅支持向前翻页)。如需获取总数count或向后翻页,请使用偏移分页。
使用 PATCH,而非 PUT
PATCH 只更新指定字段。PUT 会替换整个对象——未提供的字段可能会被清空。
并发控制与标签(NetBox 4.6+)
- 乐观并发控制(ETag / If-Match)。 详情视图响应(针对单个对象的 GET/POST/PATCH/PUT)会返回一个弱
ETag标头。后续发送 PATCH/PUT 时,通过If-Match: <etag>将其传回;如果对象期间发生了变化,服务端会以 412 Precondition Failed 拒绝请求,并返回当前 ETag。If-Match: *仅断言对象存在。省略该标头会继续采用后写入者胜出的行为。在多写入方集成中使用它,可防止更新丢失。 - 部分编辑标签(
add_tags/remove_tags)。 只写字段,用于添加或移除指定标签,而不替换整个tags集合;多个客户端各自拥有一部分标签时,可安全并发操作。限制:不能在同一请求中与tags一起使用;remove_tags仅可用于更新(不能用于创建);同一标签不能同时出现在两个列表中。
批量操作使用列表端点
没有单独的批量端点。向列表端点 POST/PATCH/DELETE 一个 JSON 数组。所有批量操作都是原子性的(全部成功或全部失败)。
# Bulk create
requests.post(f"{API_URL}/dcim/devices/", headers=headers, json=[device1, device2])
# Bulk update (each object must include "id")
requests.patch(f"{API_URL}/dcim/devices/", headers=headers, json=[{"id": 1, "status": "active"}])
# Bulk delete
requests.delete(f"{API_URL}/dcim/devices/", headers=headers, json=[{"id": 1}, {"id": 2}])
NetBox 4.7+:批量写入失败时,会返回
{"detail": "...", "errors": [...]},其中每个失败对象对应一个条目——创建操作为{"index": N, "errors": {...}},更新/删除操作为{"id": N, "errors": {...}}——因此只需修正这些对象并重新提交(整个批次仍会回滚)。添加?background=true可将大型批量写入作为任务运行:你会收到 202 和{"job": {"id", "url", "status"}},验证会延后至工作进程执行;你必须轮询job.url并检查data.status_code。请参阅 references/rest-api-patterns.md。
关键性能规则
- 在设备/VM 列表中精简
config_context。 在 4.5–4.6 中,每次请求都会针对每个对象渲染它——始终发送?omit=config_context(4.5.2+;在该版本中,?exclude=config_context效果相同),可提速 10–100 倍。在 4.7.0–4.7.2 中,它会预先渲染、缓存并始终加载——?fields=、?brief=True或?omit=config_context只能缩减负载。在 4.7.3+ 中,这些参数会再次跳过数据库注解和缓存列,因此精简仍有性能收益(低于 4.6,但确实有效)。?exclude=在所有 4.7.x 版本中都是静默无效操作——请使用?omit=config_context,以确保跨版本兼容 - 使用
?brief=True获取下拉选项和引用列表(响应大小约减少 90%) - 使用
?fields=选择特定字段 - 避免在大规模场景中使用
?q=搜索过滤器——请使用name__ic=等特定过滤器
过滤
使用查找表达式进行服务端过滤:
| 表达式 | 示例 | 说明 |
|---|---|---|
__ic | name__ic=core | 包含(不区分大小写) |
__isw | name__isw=sw- | 以……开头 |
__gte/__lte | vid__gte=100 | 数值范围 |
__isnull | primary_ip4__isnull=false | 空值检查 |
__n | status__n=offline | 不等于 |
cf_ 前缀 | cf_environment=production | 自定义字段过滤器 |
完整的 REST API 参考(包括过滤表达式、字段选择、排序、嵌套序列化器、OPTIONS 发现和错误处理),请参阅 references/rest-api-patterns.md。
GraphQL 基础知识
每个列表查询都必须分页
query {
device_list(pagination: {limit: 100, offset: 0}) {
name
status
site { name }
}
}
每个嵌套层级都必须分页
# Nested lists must also have limits
site_list(pagination: {limit: 10}) {
devices(pagination: {limit: 50}) {
interfaces(pagination: {limit: 100}) { name }
}
}
关键规则
- 使用查询优化器——对生产环境至关重要。在实际案例中,评分从 20,500 降至 17。
- 只请求需要的字段——不要过度获取数据
- 将深度控制在 ≤ 3,绝不要超过 5
- 使用
filters:参数在服务端筛选 - 性能方面优先使用 ID 筛选,而非名称筛选(可避免 JOIN)
- 根据生产数据校准优化器,以获得准确的评分
NetBox 4.5+:使用本地筛选字段(例如,在
interface_list上使用site),而不是深层嵌套的筛选路径。NetBox 4.5.2+:基于游标的分页已正式发布。传入
pagination: {start: N, limit: M}——返回id >= start的记录,并按 PK 排序。将下一页的start设为上一页最后一条记录的id+ 1。(省略start时会回退到偏移量分页。)这取代了旧的filters: {id__gte: N}深度分页变通方案;该方案仅在 4.5.2 之前的版本中需要。NetBox 4.7+:
custom_fields中的单选/多选值会解析为{value, label}对象(与 REST 相同)。服务筛选器为扁平的列表值(port_mappings、protocol、port、port__gt/gte/lt/lte),且ServiceProtocolEnum成员为TCP/UDP/SCTP(没有ROLE_前缀)。请参阅 references/graphql-patterns.md。
GraphQL 分页默认行为(与 REST 不同):
- 完全省略
pagination会返回所有匹配记录。 pagination未指定limit时,会采用 Strawberry Django 的默认值 100(而非 REST 的默认值 50)。pagination: {limit: 0}会返回 0 条记录——这与 REST 的?limit=0(返回所有记录)正好相反。MAX_PAGE_SIZE(默认值为 1000)会限制limit的上限。NetBox 4.6.1+ 还会在服务端强制执行GRAPHQL_MAX_QUERY_DEPTH,因此过深的查询可能会被直接拒绝,而不只是运行缓慢。
GraphQL 与 REST 的选择
| 使用场景 | 使用方式 |
|---|---|
| 单个对象的 CRUD | REST |
| 批量创建/更新/删除 | REST(GraphQL 仅支持读取) |
| 在一次请求中获取相关数据 | GraphQL |
| CI/CD 脚本 | REST |
| 灵活的报告 | GraphQL |
有关 GraphQL 的完整参考(包括分页策略、深度管理、避免扇出、复杂度预算和查询优化器),请参阅 references/graphql-patterns.md。
性能
影响最大的优化:
| 优化 | 影响 |
|---|---|
从列表中移除 config_context(?omit=config_context,4.5.2+;?exclude= 仅适用于 4.5–4.6,在所有 4.7.x 版本中均会被忽略) | 在 4.5–4.6 上快 10–100 倍;在 4.7.0–4.7.2 上仅减少响应负载(数据已缓存);在 4.7.3+ 上还会跳过再次执行数据库注解 |
列表使用 ?brief=True | 响应体缩小约 90% |
避免在大规模场景下使用 ?q= | 速度提升数个数量级 |
| 并行执行互不依赖的请求 | 线性提速 |
| 使用具体筛选器,而非通用搜索 | 使用针对索引优化的查询 |
有关异步分页、缓存策略、并行请求模式和基础设施注意事项,请参阅 references/performance.md。
数据建模
依赖顺序
对象必须按以下顺序创建:组织 → 站点 → DCIM 前置条件 → 机架 → 设备 → IPAM → 虚拟化 → 电路 → 连接。
设备所需的 device_type、role 和 site 必须先存在。使用 Diode 可跳过手动排序。
关键层级
- 站点:区域 → 站点组 → 站点 → 位置(递归)→ 机架 → 设备
- IPAM:RIR → 聚合地址段 → 前缀(分层)→ IP 地址;VRF 用于划分前缀/IP 的作用域
自然键、自定义字段、标签、租户
- 按
name/slug查询,而非数字 ID,让代码更易读 - 自定义字段使用
cf_前缀进行筛选。(4.7) 选择/多选值读取为{"value": "prod", "label": "Production"}——比较cf["x"]["value"],写入时使用原始值(回传该对象会导致验证失败) - 标签可用于跨对象类型分类
- 租户提供逻辑资源隔离
完整的依赖顺序、层级关系图,以及自定义字段、标签和租户隔离模式,请参阅 references/data-modeling.md。
集成工具
pynetbox(Python 客户端)
当前版本:7.9.0(2026-10-08;首个声明支持 NetBox 4.7 的版本;要求 Python 3.12+)。在 4.7 上使用 ≥ 7.9.0:该版本会展平 {value, label} 选择型自定义字段,并且更新时只发送已更改的自定义字段,因此保存包含多选自定义字段的对象可以成功(7.8.0 可能会失败)。7.9.0 还支持在 create、save()、update() 和 delete()(包括批量操作)中传入 changelog_message=,并将更多列表字段(object_types、permissions、groups、路由目标、配置上下文范围)作为集合进行比较,因此重新排序不再触发 PATCH。
import pynetbox
nb = pynetbox.api("https://netbox.example.com", token="nbt_abc123.xxxxxxxxxxxxxxxx",
pagination="cursor") # 7.8+: keyset paging on NetBox 4.6+; falls back to offset on older servers
devices = nb.dcim.devices.filter(site="nyc-dc1", status="active") # Auto-paginated
device = nb.dcim.devices.get(name="switch-01")
device.status = "planned"
device.save() # Uses PATCH
pagination="cursor"为顺序执行(会忽略threading=True),不能与ordering组合使用,并且len(record_set)会额外产生一次计数请求。- 来自
pynetbox.extensions(7.8+)的extensions=[BranchingExtension]/[CustomObjectsExtension]可添加类型化记录和插件操作——参阅 Branching。 - 在 NetBox 4.7 上,选择字段的
record.custom_fields["x"]是一个{"value", "label"}字典。
Diode(数据摄取)
对于批量摄取,请使用 Diode,而不是直接使用 API。按名称指定依赖项——Diode 会自动解析或创建它们。无需安排依赖顺序。
from netboxlabs.diode.sdk import DiodeClient
from netboxlabs.diode.sdk.ingester import Device, Entity
with DiodeClient(target="grpc://diode.example.com:8080/diode",
app_name="discovery", app_version="1.0.0") as client:
device = Device(name="switch-01", device_type="Catalyst 9300",
manufacturer="Cisco", site="NYC-DC1", role="Access Switch")
client.ingest([Entity(device=device)])
适用 Diode 的场景:网络发现、批量迁移、创建大量相关对象的脚本。 适用 REST/GraphQL 的场景:读取数据、单个对象 CRUD、复杂查询。
批量摄取、嵌套对象、试运行模式、身份验证和受支持的实体类型,请参阅 references/diode-integration.md。
Webhook
配置 NetBox 通过 webhook 推送更改。务必验证 X-Hook-Signature 标头(HMAC-SHA512)。事件包括 created、updated、deleted,并附带完整对象数据和更改前/后的快照。
更改跟踪
查询 extras.object_changes 获取审计记录——其中包括时间戳、操作、用户以及更改前/后的数据。
分支(插件)
需要 netbox-branching 插件——NetBox 4.7 使用 v1.2.x,NetBox 4.4–4.6 使用 v1.1.x。插件设置和工作流: netbox-branching。
生命周期:创建 → 等待(PROVISIONING→READY)→ 工作 → 同步 → 合并
- 上下文标头:
X-NetBox-Branch: {schema_id}——使用 8 个字符的schema_id,而非名称或数字 ID - 异步操作:同步/合并/还原会返回 Job 对象——轮询
job["url"],直到status == "completed" - 试运行:所有异步操作都接受
{"commit": false}进行验证 - pynetbox 7.8+:
pynetbox.api(..., extensions=[BranchingExtension])提供branch.sync()/merge()/revert()(返回 Job 记录;存在冲突时会在确认前于exc.error中返回 409),并且with nb.activate_branch(branch):会自动为你设置标头
完整的分支生命周期、上下文标头用法、异步作业轮询和会话封装模式,请参阅 references/branching-patterns.md。
版本说明
NetBox 4.7.3(2026-10-13)
- 在设备/VM 列表或详情读取中使用
?omit=config_context、不带?fields=,或使用?brief=True,会再次跳过 config-context 数据库注释和缓存列(#23288;?exclude=仍然不起作用);现在?background=true批量写入会将请求标头和查询字符串一并传给工作进程,因此X-NetBox-Branch会生效(#23247——在 4.7.0–4.7.2 中该标头会被丢弃,写入会落到 main)。请运行 ≥ 4.7.3:4.7.0/4.7.1 会将令牌明文泄露到作业结果中;4.7.3 增加了与分支兼容的后台写入和跳过 config-context 的优化。
NetBox 4.7(2026-09-02;运行 ≥ 4.7.3)
- 在所有 4.7.x 版本中,
?exclude=config_context都会被静默忽略;设备/VM 上的config_context会预先渲染并缓存。在 4.7.0–4.7.2 中,它总会被加载(?fields=、?omit=config_context、?brief=True只会缩减载荷);在 4.7.3+ 中,这些参数还会跳过数据库操作。 - 选择/多选自定义字段读取时会返回
{value, label}(REST + GraphQL);写入时使用原始值。 - 批量写入:
?background=true→ 202 + 作业(轮询作业;带有If-Match时返回 400,没有工作进程时返回 503);批量创建/更新失败时会按对象返回errors。批量操作仍然是全有或全无。在分支内,4.7.0–4.7.2 会丢弃X-NetBox-Branch(写入会落到 main)——4.7.3+ 则会传递该标头。 - 令牌:创建时
token为只读;/api/users/tokens/不接受?background=true(4.7.2——更早的 4.7.x 会将明文泄露到作业结果中);通过 REST 执行脚本需要启用写入权限的令牌。 - 服务:
protocol/ports→port_mappings(["tcp/53", "udp/53"]);旧的成对字段已弃用,将在 5.0 移除;protocol__ic风格和port__empty查询已移除。参见 references/data-modeling.md。 - Interface/VMInterface 的
mac_address可写入(创建或更新主 MAC);MACAddress.is_primary为只读。 - 新增端点:
dcim/cooling-sources|cooling-feeds|cooling-intakes|cooling-outflows|cooling-intake-templates|cooling-outflow-templates/、dcim/module-bay-types/。新增字段:end_of_life(DeviceType/ModuleType)、channels/channel_id(Interface)、Job.execution_time、Webhook.timeout、CustomField.status/nulls_first。 - 升级前提(PostgreSQL 15+、
ltree、Redis 6+)以及耗时较长的 MPTT→ltree 迁移详见 netbox-administration。
NetBox 4.6
- REST 游标分页(
?start=)、ETag/If-Match、add_tags/remove_tags;v1 令牌已弃用(5.0 移除);明文令牌仅返回一次(4.6.1+);服务器端强制执行GRAPHQL_MAX_QUERY_DEPTH(4.6.1+);VM 的cluster可选。