mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-08 19:27:14 +00:00
docs(api): mark collection responses nullable (#6430)
* docs(api): mark collection responses nullable Describe allLinks and panel log response objects as nullable string arrays so generated clients accept the existing nil-slice wire format. Pin both schemas with buildSpec regression assertions and regenerate the OpenAPI copies. * docs(api): include nullable Xray log responses Allow generated response arrays to opt into nullability while retaining their schema references and Go-derived examples. Apply this to Xray logs, whose nil slices already serialize as null, and pin the schema and example through buildSpec.
This commit is contained in:
@@ -4340,7 +4340,13 @@
|
||||
"msg": {
|
||||
"type": "string"
|
||||
},
|
||||
"obj": {}
|
||||
"obj": {
|
||||
"type": "array",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
@@ -6399,6 +6405,7 @@
|
||||
},
|
||||
"obj": {
|
||||
"type": "array",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -6480,6 +6487,7 @@
|
||||
},
|
||||
"obj": {
|
||||
"type": "array",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LogEntry"
|
||||
}
|
||||
|
||||
@@ -4340,7 +4340,13 @@
|
||||
"msg": {
|
||||
"type": "string"
|
||||
},
|
||||
"obj": {}
|
||||
"obj": {
|
||||
"type": "array",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
@@ -6399,6 +6405,7 @@
|
||||
},
|
||||
"obj": {
|
||||
"type": "array",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -6480,6 +6487,7 @@
|
||||
},
|
||||
"obj": {
|
||||
"type": "array",
|
||||
"nullable": true,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/LogEntry"
|
||||
}
|
||||
|
||||
@@ -245,7 +245,13 @@ function buildOperation(ep, tag) {
|
||||
);
|
||||
}
|
||||
const ref = { $ref: `#/components/schemas/${ep.responseSchema}` };
|
||||
objSchema = ep.responseSchemaArray ? { type: 'array', items: ref } : ref;
|
||||
objSchema = ep.responseSchemaArray
|
||||
? {
|
||||
type: 'array',
|
||||
...(ep.responseSchemaArrayNullable ? { nullable: true } : {}),
|
||||
items: ref,
|
||||
}
|
||||
: ref;
|
||||
if (successExample === undefined) {
|
||||
successExample = { success: true, obj: ep.responseSchemaArray ? [obj] : obj };
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ export interface Endpoint {
|
||||
bodyRequiredOneOf?: string[];
|
||||
responseSchema?: string;
|
||||
responseSchemaArray?: boolean;
|
||||
responseSchemaArrayNullable?: boolean;
|
||||
responseObjectSchema?: Record<string, unknown>;
|
||||
responses?: Record<string, Record<string, unknown>>;
|
||||
security?: readonly Record<string, readonly string[]>[];
|
||||
@@ -265,6 +266,7 @@ export const sections: readonly Section[] = [
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/panel/api/inbounds/allLinks',
|
||||
responseObjectSchema: { type: 'array', nullable: true, items: { type: 'string' } },
|
||||
summary:
|
||||
'Return every protocol URL (vless://, vmess://, trojan://, ss://, hysteria://, mtproto) across all inbounds and all of their clients. Links are rendered through the subscription engine, so the configured remark template (name-only display part) is applied per client — the same output the client info/QR pages use. Protocols without a URL form (socks, http, mixed, wireguard, dokodemo, tunnel) contribute nothing. Used by the panel’s "Export all inbound links" action.',
|
||||
response:
|
||||
@@ -709,7 +711,7 @@ export const sections: readonly Section[] = [
|
||||
},
|
||||
],
|
||||
body: 'level=info&syslog=false',
|
||||
responseObjectSchema: { type: 'array', items: { type: 'string' } },
|
||||
responseObjectSchema: { type: 'array', nullable: true, items: { type: 'string' } },
|
||||
response:
|
||||
'{\n "success": true,\n "obj": [\n "2025/01/01 12:00:00 [INFO] Server started",\n "2025/01/01 12:00:01 [INFO] Xray is running"\n ]\n}',
|
||||
},
|
||||
@@ -751,6 +753,7 @@ export const sections: readonly Section[] = [
|
||||
body: 'filter=error&showDirect=false&showBlocked=true&showProxy=true',
|
||||
responseSchema: 'LogEntry',
|
||||
responseSchemaArray: true,
|
||||
responseSchemaArrayNullable: true,
|
||||
},
|
||||
{
|
||||
method: 'POST',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { buildSpec } from '../../scripts/build-openapi.mjs';
|
||||
import { EXAMPLES } from '../generated/examples';
|
||||
|
||||
interface OpenApiSchema {
|
||||
$ref?: string;
|
||||
@@ -31,7 +32,7 @@ interface OpenApiOperation {
|
||||
responses: Record<
|
||||
string,
|
||||
{
|
||||
content?: Record<string, { schema: OpenApiSchema }>;
|
||||
content?: Record<string, { schema: OpenApiSchema; example?: unknown }>;
|
||||
}
|
||||
>;
|
||||
security?: Record<string, never[]>[];
|
||||
@@ -127,15 +128,30 @@ describe('generated OpenAPI runtime contracts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('documents all inbound links as a nullable string array', () => {
|
||||
expect(responseObjectSchema('/panel/api/inbounds/allLinks')).toEqual({
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: { type: 'string' },
|
||||
});
|
||||
});
|
||||
|
||||
it('uses the runtime REST response schemas', () => {
|
||||
expect(responseObjectSchema('/panel/api/server/logs/{count}', 'post')).toEqual({
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: { type: 'string' },
|
||||
});
|
||||
expect(responseObjectSchema('/panel/api/server/xraylogs/{count}', 'post')).toEqual({
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: { $ref: '#/components/schemas/LogEntry' },
|
||||
});
|
||||
expect(
|
||||
operation('/panel/api/server/xraylogs/{count}', 'post').responses['200'].content?.[
|
||||
'application/json'
|
||||
].example,
|
||||
).toEqual({ success: true, obj: [EXAMPLES.LogEntry] });
|
||||
expect(responseObjectSchema('/panel/api/server/getNewUUID')).toEqual({
|
||||
$ref: '#/components/schemas/NewUUIDResponse',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user