modified: backend/src/config/dynamicSwagger.ts
modified: backend/src/controllers/endpointController.ts new file: backend/src/migrations/009_add_response_schema.sql modified: backend/src/types/index.ts modified: frontend/src/pages/EndpointEditor.tsx modified: frontend/src/types/index.ts
This commit is contained in:
@@ -75,9 +75,17 @@ export default function EndpointEditor() {
|
||||
aql_query_params: endpointData.aql_query_params || {},
|
||||
detailed_response: endpointData.detailed_response || false,
|
||||
});
|
||||
setResponseSchemaText(
|
||||
endpointData.response_schema
|
||||
? JSON.stringify(endpointData.response_schema, null, 2)
|
||||
: ''
|
||||
);
|
||||
}
|
||||
}, [endpointData]);
|
||||
|
||||
const [responseSchemaText, setResponseSchemaText] = useState('');
|
||||
const [responseSchemaExpanded, setResponseSchemaExpanded] = useState(false);
|
||||
const [responseSchemaError, setResponseSchemaError] = useState('');
|
||||
const [editingQueryIndex, setEditingQueryIndex] = useState<number | null>(null);
|
||||
const [showScriptCodeEditor, setShowScriptCodeEditor] = useState(false);
|
||||
const [parametersExpanded, setParametersExpanded] = useState(true);
|
||||
@@ -215,7 +223,17 @@ export default function EndpointEditor() {
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
saveMutation.mutate(formData);
|
||||
let parsedSchema = null;
|
||||
if (responseSchemaText.trim()) {
|
||||
try {
|
||||
parsedSchema = JSON.parse(responseSchemaText);
|
||||
} catch {
|
||||
setResponseSchemaError('Некорректный JSON');
|
||||
setResponseSchemaExpanded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
saveMutation.mutate({ ...formData, response_schema: parsedSchema });
|
||||
};
|
||||
|
||||
// cURL generator
|
||||
@@ -738,6 +756,45 @@ export default function EndpointEditor() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Response schema */}
|
||||
<div className="border border-gray-200 rounded-lg">
|
||||
<div
|
||||
className="flex items-center justify-between p-3 bg-gray-50 cursor-pointer hover:bg-gray-100 rounded-t-lg"
|
||||
onClick={() => setResponseSchemaExpanded(!responseSchemaExpanded)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{responseSchemaExpanded ? <ChevronUp size={18} /> : <ChevronDown size={18} />}
|
||||
<label className="text-sm font-medium text-gray-700 cursor-pointer">
|
||||
Схема ответа 200 (Swagger)
|
||||
</label>
|
||||
{responseSchemaText.trim() && (
|
||||
<span className="px-2 py-0.5 bg-green-100 text-green-700 rounded-full text-xs">задана</span>
|
||||
)}
|
||||
{responseSchemaError && (
|
||||
<span className="px-2 py-0.5 bg-red-100 text-red-700 rounded-full text-xs">{responseSchemaError}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{responseSchemaExpanded && (
|
||||
<div className="p-4 bg-white rounded-b-lg space-y-2">
|
||||
<p className="text-xs text-gray-500">
|
||||
JSON Schema в формате OpenAPI для документирования ответа. Если не задана — используется схема по умолчанию.
|
||||
</p>
|
||||
<textarea
|
||||
value={responseSchemaText}
|
||||
onChange={(e) => {
|
||||
setResponseSchemaText(e.target.value);
|
||||
setResponseSchemaError('');
|
||||
}}
|
||||
className="input w-full font-mono text-xs"
|
||||
rows={10}
|
||||
placeholder={'{\n "type": "array",\n "items": {\n "type": "object",\n "properties": {\n "id": { "type": "number" },\n "name": { "type": "string" }\n }\n }\n}'}
|
||||
spellCheck={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Checkboxes */}
|
||||
<div className="flex flex-wrap items-center gap-6">
|
||||
<label className="flex items-center gap-2">
|
||||
|
||||
@@ -81,6 +81,7 @@ export interface Endpoint {
|
||||
aql_query_params?: Record<string, string>;
|
||||
// Response format
|
||||
detailed_response?: boolean;
|
||||
response_schema?: object | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user