This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
LLMApi: OpenAPI 动态模拟生成器@:装载任何 SpecMS K2
Wednesday, 05 November 2025
这篇文章主要是作为我发行文档 .QI It'Q的金字塔软件包的一部分产生的人工智能, 我把它放在这里很有意思 所以如果这是个问题 请忽略它 @.Q
一. 导言导言 导言 导言 导言
您是否需要测试一个 API 尚未准备好的 '}( ?}) 或者想要在不设速率限制的情况下开发离线性能...?。 OpenAPI动态模拟生成器允许您装入任何OpenAPI规格, 并立即用符合实际的 <,> LLM=-生成数据*.}创建完整的-#功能模拟API?
没有配置文件@.没有手动创建端点 @ . 只要将它指向 OpenAPI spec 并开始请求\ MS K2
你可以找到 吉特Hub在这里 所有公共域等 ... *

问题=:}AIP 依赖性区块开发
现代应用程序取决于几十个外部APIs.}在开发期间 <%,}你面临数项挑战<_:}*
graph TD
A[Your App] --> B{External API}
B -->|Not Ready| C[Development Blocked]
B -->|Rate Limited| D[Can't Test Freely]
B -->|Requires Auth| E[Complex Setup]
B -->|Expensive| F[Cost Concerns]
B -->|Unreliable| G[Flaky Tests]
传统解决办法涉及:
- 手写模拟回应@(tidious,}成为过时的 @)
- 正在记录“/”重放 HTTP 流量“ @ (_ brittle@ MS K2} 难以维护的 hard to keep k3
- 使用硬码固定装置 @ (@unacticatetic=,} does'_ t覆盖边缘情况@)+%
解答@:动态的 OpenAPI 模拟
将系统指向任何 OpenAPI spec,,并自动标记为:
- 解析规格
- 发现所有终点
- 使用 LLM 生成现实的模拟数据
- 将模拟APIP服务在本地机器上
sequenceDiagram
participant Dev as Developer
participant System as Mock System
participant Spec as OpenAPI Spec
participant LLM as Local LLM
Dev->>System: Load spec from URL/file
System->>Spec: Parse OpenAPI document
Spec-->>System: Endpoints, schemas, descriptions
System->>System: Register dynamic routes
Dev->>System: GET /petstore/pet/123
System->>LLM: Generate data for "Pet" schema
LLM-->>System: Realistic pet data
System-->>Dev: {"id": 123, "name": "Max", ...}
如何运作
建筑结构概览
OpenAPI系统由几个协调组件组成 :
graph TB
A[HTTP Request] --> B{Route Matches?}
B -->|No| C[404 Not Found]
B -->|Yes| D[DynamicOpenApiManager]
D --> E[Find Matching Endpoint]
E --> F[OpenApiRequestHandler]
F --> G[Extract Schema from Spec]
G --> H[Build LLM Prompt]
H --> I[PromptBuilder]
I --> J[Include Context?]
J -->|Yes| K[OpenApiContextManager]
J -->|No| L[LLM Client]
K --> L
L --> M[Get Response]
M --> N[JsonExtractor]
N --> O[Return Mock Data]
密钥元件@: @%
- 动态开放管理器 - 管理已装入的参数和路线匹配
- Open spiSpeecloader 打开光线 - 获取并解析 OpenAPI 文件
- OpenApi 请求挂载器 - 生成匹配端点的响应
- 即时建筑 - 创建 OpenAPI 方案下的 LLM 提示
- OpenApicon Text 管理器 @- 保持调用一致@( optional)
装入指定
可以从三个来源装入光谱@: @%
1. 远程 URL
POST /api/openapi/specs
Content-Type: application/json
{
"name": "petstore",
"source": "https://petstore3.swagger.io/api/v3/openapi.json",
"basePath": "/petstore"
}
2. 本地文件
POST /api/openapi/specs
Content-Type: application/json
{
"name": "my-api",
"source": "./specs/my-api.yaml",
"basePath": "/api/v1"
}
3. 数据 URL {(}_Base\64 编码=)
POST /api/openapi/specs
Content-Type: application/json
{
"name": "inline-api",
"source": "data:application/json;base64,eyJvcGVuYXBpIjoiMy...",
"basePath": "/api"
}
标注加载进程
这里“ '} ” 当你装入一个 ppec : 时会发生什么?
public async Task<SpecLoadResult> LoadSpecAsync(
string name,
string source,
string? basePath = null,
string? contextName = null)
{
// 1. Use scoped service factory for OpenApiSpecLoader
using var scope = _scopeFactory.CreateScope();
var specLoader = scope.ServiceProvider
.GetRequiredService<OpenApiSpecLoader>();
// 2. Load the OpenAPI document
var document = await specLoader.LoadSpecAsync(source);
// 3. Determine base path from spec or parameter
var effectiveBasePath = basePath
?? document.Servers?.FirstOrDefault()?.Url
?? "/api";
// 4. Store spec with configuration
var config = new OpenApiSpecConfig
{
Name = name,
Source = source,
Document = document,
BasePath = effectiveBasePath,
ContextName = contextName,
LoadedAt = DateTimeOffset.UtcNow
};
_specs.AddOrUpdate(name, config, (_, __) => config);
// 5. Notify listeners via SignalR
await NotifySpecLoaded(name, effectiveBasePath);
return new SpecLoadResult
{
Name = name,
BasePath = effectiveBasePath,
EndpointCount = CountEndpoints(document),
Success = true
};
}
动态线路匹配
当一个请求到达时, 系统与所有已装入的speces:匹配
public OpenApiEndpointMatch? FindMatchingEndpoint(string path, string method)
{
// Try each loaded spec
foreach (var spec in _specs.Values)
{
// Remove base path prefix
var relativePath = path;
if (path.StartsWith(spec.BasePath))
{
relativePath = path.Substring(spec.BasePath.Length);
}
// Find matching path in OpenAPI document
var (pathTemplate, operation) = FindOperation(
spec.Document,
relativePath,
method);
if (operation != null)
{
return new OpenApiEndpointMatch
{
Spec = spec,
PathTemplate = pathTemplate,
Operation = operation,
Method = ParseMethod(method)
};
}
}
return null;
}
请求处理
一旦找到匹配的端点 @ , 处理器生成响应Q:\
public async Task<string> HandleRequestAsync(
HttpContext context,
OpenApiDocument document,
string path,
OperationType method,
OpenApiOperation operation,
string? contextName = null,
CancellationToken cancellationToken = default)
{
// 1. Extract request body
var requestBody = await ReadRequestBodyAsync(context.Request);
// 2. Get success response schema
var shape = ExtractResponseSchema(operation);
// 3. Get context history if using contexts
var contextHistory = !string.IsNullOrWhiteSpace(contextName)
? _contextManager.GetContextForPrompt(contextName)
: null;
// 4. Build prompt from OpenAPI metadata
var description = operation.Summary ?? operation.Description;
var prompt = _promptBuilder.BuildPrompt(
method.ToString(),
path,
requestBody,
new ShapeInfo { Shape = shape },
streaming: false,
description: description,
contextHistory: contextHistory);
// 5. Get response from LLM
var rawResponse = await _llmClient.GetCompletionAsync(
prompt,
cancellationToken);
// 6. Extract clean JSON
var jsonResponse = JsonExtractor.ExtractJson(rawResponse);
// 7. Store in context if configured
if (!string.IsNullOrWhiteSpace(contextName))
{
_contextManager.AddToContext(
contextName,
method.ToString(),
path,
requestBody,
jsonResponse);
}
return jsonResponse;
}
Schema 采掘
系统从 OpenAPI 定义中提取响应方案@:
private string? ExtractResponseSchema(OpenApiOperation operation)
{
// Look for successful response (2xx)
var successResponse = operation.Responses
.FirstOrDefault(r => r.Key.StartsWith("2"))
.Value;
if (successResponse == null)
return null;
// Get JSON content
var jsonContent = successResponse.Content
.FirstOrDefault(c => c.Key.Contains("json"))
.Value;
if (jsonContent?.Schema == null)
return null;
// Convert OpenAPI schema to JSON Schema
return ConvertToJsonSchema(jsonContent.Schema);
}
private string ConvertToJsonSchema(OpenApiSchema schema)
{
// Recursively build JSON Schema representation
var builder = new StringBuilder();
builder.Append("{");
if (schema.Type != null)
{
builder.Append($"\"type\":\"{schema.Type}\"");
}
if (schema.Properties?.Count > 0)
{
builder.Append(",\"properties\":{");
var props = schema.Properties
.Select(p => $"\"{p.Key}\":{ConvertToJsonSchema(p.Value)}");
builder.Append(string.Join(",", props));
builder.Append("}");
}
if (schema.Items != null)
{
builder.Append(",\"items\":");
builder.Append(ConvertToJsonSchema(schema.Items));
}
builder.Append("}");
return builder.ToString();
}
世界使用量
例如::
Let''s 走通过 嘲弄经典的宠物商店API:
*步骤 \ 1: 装入闪光
POST /api/openapi/specs
Content-Type: application/json
{
"name": "petstore",
"source": "https://petstore3.swagger.io/api/v3/openapi.json",
"basePath": "/petstore"
}
回应::
{
"name": "petstore",
"basePath": "/petstore",
"endpointCount": 19,
"endpoints": [
{"path": "/petstore/pet", "method": "POST"},
{"path": "/petstore/pet/{petId}", "method": "GET"},
{"path": "/petstore/pet/findByStatus", "method": "GET"},
...
],
"success": true
}
使用模拟末点
现在所有19的终点都可用\ :
### Get a pet by ID
GET /petstore/pet/123
### Response (auto-generated):
{
"id": 123,
"name": "Max",
"category": {
"id": 1,
"name": "Dogs"
},
"photoUrls": [
"https://example.com/max1.jpg"
],
"tags": [
{"id": 1, "name": "friendly"},
{"id": 2, "name": "trained"}
],
"status": "available"
}
### Find pets by status
GET /petstore/pet/findByStatus?status=available
### Response (auto-generated array):
[
{
"id": 42,
"name": "Buddy",
"status": "available",
...
},
{
"id": 43,
"name": "Luna",
"status": "available",
...
}
]
步骤“3:”检查光谱
GET /api/openapi/specs/petstore
### Shows full details:
### - All endpoints
### - Load time
### - Context configuration
### - Base path
*步骤 4: {如果插件改变则重新装入
POST /api/openapi/specs/petstore/reload
步骤 @5: 移除完成后删除
DELETE /api/openapi/specs/petstore
多重分层同时
您可以同时加载多个参数@ , @ 每个人的基路径\ :} @ action: check
### Load Petstore at /petstore
POST /api/openapi/specs
{"name": "petstore", "source": "...", "basePath": "/petstore"}
### Load GitHub API at /github
POST /api/openapi/specs
{"name": "github", "source": "...", "basePath": "/github"}
### Load Stripe API at /stripe
POST /api/openapi/specs
{"name": "stripe", "source": "...", "basePath": "/stripe"}
### All three APIs now available simultaneously:
GET /petstore/pet/123
GET /github/users/octocat
GET /stripe/customers/cus_123
带有上下文的特征
为了更多现实性 , 给一个spec:\ 指定上下文
POST /api/openapi/specs
Content-Type: application/json
{
"name": "petstore",
"source": "https://petstore3.swagger.io/api/v3/openapi.json",
"basePath": "/petstore",
"contextName": "petstore-session"
}
现在所有宠物店端点都共享相同的上下文@: @%
### Create a pet
POST /petstore/pet
{"name": "Max", "status": "available"}
### Response: {"id": 42, "name": "Max", "status": "available"}
### Get the pet (will reference same ID and name)
GET /petstore/pet/42
### Response: {"id": 42, "name": "Max", "status": "available"}
### Notice: Consistent ID and name from context
测试终点
测试端点允许您尝试端点而不提出真正的请求@ : @
POST /api/openapi/test
Content-Type: application/json
{
"specName": "petstore",
"path": "/pet/123",
"method": "GET"
}
### Returns mock response without affecting routes
此功能对 @ : @ action
- 整合前预览响应
- 单独测试特定终点
- 调试计划问题
管理统一UI
视觉管理访问@,_ http://localhost:5116/OpenApi:
graph TD
A[OpenAPI Manager UI] --> B[Load Spec Section]
A --> C[Spec List]
A --> D[Context Viewer]
B --> E[URL Input]
B --> F[JSON Input]
B --> G[Context Configuration]
C --> H[Spec Card]
H --> I[Reload Button]
H --> J[Delete Button]
H --> K[View Endpoints]
D --> L[Active Contexts]
L --> M[Context Details]
L --> N[Clear Context]
功能@: @%
- 拖放@ - @ 和 @ MS K1 @ put spec 文件上传
- 活端点发现 @- 立即看到所有终点
- One - 点击测试 - 用按钮测试任何端点
- Real-}时间通知 - 信号R 当标本装入时更新@ info: status
- 语法突出 美丽的JSON应答显示
- 背景管理 - 视图和清晰的背景
高级特征
路径图参数
路径参数被自动提取@: @%
# OpenAPI Spec
/pet/{petId}:
get:
parameters:
- name: petId
in: path
schema:
type: integer
GET /petstore/pet/123
### LLM receives: "Generate data for Pet with petId=123"
### Response: {"id": 123, ...}
查询参数
查询参数影响响应@: @
/pet/findByStatus:
get:
parameters:
- name: status
in: query
schema:
type: string
enum: [available, pending, sold]
GET /petstore/pet/findByStatus?status=available
### LLM receives: "Generate array of Pets with status=available"
### Response: [{"status": "available", ...}, ...]
请求机构
POST/PUT 机构包含在提示@:中
/pet:
post:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
POST /petstore/pet
Content-Type: application/json
{"name": "Max", "status": "available"}
### LLM receives: "Generate response for creating Pet with name=Max, status=available"
### Response: {"id": 42, "name": "Max", "status": "available"}
说明和摘要
OpenAPI 描述指导 LLM: @%
/pet/{petId}:
get:
summary: Find pet by ID
description: Returns a single pet based on the ID provided
这些都包含在快报“,”中 帮助LLM了解终点 “'”目的“MS K2”
反应状态法
系统使用第一个成功的 @(2_xx_)}回应@:
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
'404':
description: Pet not found
只有 200 schema 用于模拟代号@(404目前尚未模拟 @).}
信号R Real=-}时间更新
当装入 specs\ @ / deleted\ MS K1 时, UI 通过 SignalR: 接收 realQ-\ 时间通知 *
public async Task NotifySpecLoaded(string name, string basePath)
{
await _hubContext.Clients.All.SendAsync("SpecLoaded", new
{
name,
basePath,
timestamp = DateTimeOffset.UtcNow
});
}
public async Task NotifySpecDeleted(string name)
{
await _hubContext.Clients.All.SendAsync("SpecDeleted", new
{
name,
timestamp = DateTimeOffset.UtcNow
});
}
JavaScript 用户界面代码@: @%
const connection = new signalR.HubConnectionBuilder()
.withUrl('/hubs/openapi')
.build();
connection.on('SpecLoaded', (data) => {
showNotification(`Spec "${data.name}" loaded at ${data.basePath}`, 'success');
refreshSpecList();
});
connection.on('SpecDeleted', (data) => {
showNotification(`Spec "${data.name}" deleted`, 'info');
refreshSpecList();
});
格式支持
系统支持@: @%
- OpenAPI 3.0.x
- OpenAPI 3.1.x
- 斯瓦格 2.0
- JSON 格式
- YAML 格式
JSON和YAML的特征都自动检测并分析
最佳做法
1. 使用描述性插件名称
Bad: {"name": "spec1", ...}
Good: {"name": "github-v3", ...}
2. 设置适当的基础路径
使用独特的基准路径来避免冲突@: @%
### Good separation
/petstore/...
/github/...
/stripe/...
### Bad (conflicts!)
/api/... (multiple specs)
specs change 时重新装入 3.
如果您的 OpenAPI spec 已被更新@ , @ reload it:}
POST /api/openapi/specs/my-api/reload
4. 相关调用使用背景
POST /api/openapi/specs
{
"name": "petstore",
"source": "...",
"contextName": "test-session"
}
### Now all petstore calls maintain consistency
@5. 测试后清理
删除您're 不再使用@ :
DELETE /api/openapi/specs/old-spec
限制
- 反应状态法 @- @ 仅成功 @ (2_xx#)}回应被嘲笑
- 验证 - Auth 信头被接受但未经验证
- 审定 *- 请求对计划进行验证时未执行
- 状态国 “- ” 没有实际数据库“; 数据每次生成新鲜数据, @( 除非使用上下文@)
- 业绩表现 实绩 “-LLM 一代”加上“(~100-500ms”,
与常规模拟末端点整合
OpenAPI 特征与常规平行工作 /api/mock 端点@: @%
### OpenAPI-based (from spec)
GET /petstore/pet/123
### Uses Pet schema from OpenAPI spec
### Regular mock (shape-based)
GET /api/mock/custom?shape={"id":0,"name":"string"}
### Uses explicit shape parameter
两者都使用相同的底部LLM,但在如何提供方案上却各有不同。
业绩优化
缓缓
在内存中缓存已装入的参数@ :
private readonly ConcurrentDictionary<string, OpenApiSpecConfig> _specs = new();
使用寿命
DynamicOpenApiManager 是一个单子@ ,} 所以应用程序使用寿命的特性仍然被装入\ MS K1 @
平行镜表加载
多个特性可以平行装入@ : @
### Send these simultaneously
POST /api/openapi/specs {"name": "spec1", ...}
POST /api/openapi/specs {"name": "spec2", ...}
POST /api/openapi/specs {"name": "spec3", ...}
全部三个将同时装入 , 不是顺序\ MPK1\
排除故障
Spec Won'% t 加载
问题M: 显示装入失败
解决方案#:
- 检查 URL 可访问
- 校验已存在的本地路径@) @% 1
- 确保 JSON/YAML 有效
- 寻找远程 URLs=% )
未找到结束点
问题M: 404在预期端点
解决方案#:
- 校验基路 #:#
/petstore+/pet/123=/petstore/pet/123 - 检查 pec 实际定义此路径
- 确保 HTTP 方法与 @ (+GET 相对于 POPST@)+%
回应('t匹配 Schema)
问题M: 生成的数据与预期的 schema 匹配@ ' @ t
解决方案#:
- 检查规格中的图案是否正确
- 校验您是否看到正确回应@(200 @ vs @201)}
- 记住:LLM一代是概率=,不是决定性的
结论结论
OpenAPI 动态模拟鼠标生成器将任何OpenAPI规格转换成一个完全的“-”功能模拟API, 在秒@. 没有手动配置,没有硬码响应 @,没有维护管理@MS K4
LLM产生符合您的 schemas ,的不同数据,
- 前端开发 后端正在建设中
- 集成测试 不打实际 API
- 离线发展 连接有限时
- 装入测试 无配额问题
- 原型设计 快速新特性
加上API的背景语境@,,你得到的模拟API能够保持所有电话之间的一致性\ ,提供更现实的生产系统模拟=.
模拟API的未来是充满活力的#,智能_,,