La próxima versión de sgcOpenAPI — la 2026.6, prevista para junio — incorpora un componente totalmente nuevo: TsgcHTTPServer_OpenAPI. Se trata de un único componente Delphi autónomo que aloja un servicio OpenAPI 3.0 con un servidor HTTP integrado. Colócalo en un formulario, apúntalo a una especificación (o genérala desde una clase Delphi con atributos RTTI), establece Active := True y tendrás una API REST documentada con Swagger UI servido automáticamente.
El cambio principal es que sgcOpenAPI ya no necesita sgcWebSockets para alojar un servidor HTTP. El nuevo componente se distribuye, empaqueta e instala íntegramente desde sgcOpenAPI. Si ya usas sgcWebSockets, el componente anterior TsgcWSServer_API_OpenAPI sigue funcionando sin cambios — ambos comparten el mismo motor internamente.
Lo que obtienes en un solo componente
TsgcHTTPServer_OpenAPI agrupa tres elementos:
- Un servidor HTTP integrado (basado en Indy) con las habituales propiedades
Bindings,PortyActive. - El motor OpenAPI: análisis de la especificación, enrutamiento mediante plantillas de ruta con segmentos
{paramName}, validación JSON-Schema, CORS y gestión de excepciones. - Dos endpoints servidos automáticamente: la especificación en
/openapi.jsony un Swagger UI en/docs. Ambos están activados por defecto y se pueden alternar enOpenAPIOptions.Endpoint.
Inicio rápido — el ejemplo mínimo
Esto es todo lo que necesitas para alojar un servidor OpenAPI funcional con Swagger UI:
uses
sgcHTTPServer_OpenAPI;
var
oServer: TsgcHTTPServer_OpenAPI;
begin
oServer := TsgcHTTPServer_OpenAPI.Create(nil);
try
oServer.Bindings.Add.Port := 8080;
oServer.LoadFromFile('petstore.json');
oServer.OnRequest := MyOnRequest;
oServer.Active := True;
Readln;
finally
oServer.Free;
end;
end;
Accede a http://localhost:8080/docs para ver el Swagger UI y a http://localhost:8080/openapi.json para la especificación. Cada operación definida en la especificación se enruta a tu manejador MyOnRequest con el operationId resuelto y un contexto de solicitud completamente construido.
Spec-First — carga un archivo OpenAPI 3.0 existente
Si ya dispones de un archivo OpenAPI 3.0 en JSON o YAML (Petstore, un contrato de API interno, un esquema público que quieras simular), spec-first es la forma más rápida de servirlo. LoadFromFile lee y analiza la especificación, construye una tabla de rutas a partir de la sección paths y compara cada solicitud entrante con ella.
El operationId de cada ruta es la clave de despacho. Dentro de OnRequest gestionas cada operación por turno:
uses
sgcHTTP_OpenAPI_Server, sgcHTTP_OpenAPI_Server_Engine,
sgcHTTPServer_OpenAPI;
procedure TForm1.OnOpenAPIRequest(Sender: TObject;
const aOperationId: string; const aContext: TsgcOpenAPIServerContext;
var Handled: Boolean);
begin
Handled := True;
if aOperationId = 'listPets' then
HandleListPets(aContext)
else if aOperationId = 'getPetById' then
HandleGetPetById(aContext)
else if aOperationId = 'createPet' then
HandleCreatePet(aContext)
else
Handled := False;
end;
procedure TForm1.HandleGetPetById(const aContext: TsgcOpenAPIServerContext);
var
vId, vPetJSON: string;
begin
vId := aContext.PathParamAsString('petId');
vPetJSON := FPets.Values[vId];
if vPetJSON <> '' then
aContext.RespondJSON(200, vPetJSON)
else
aContext.RespondError(404, 'Not Found', 'Pet ' + vId + ' not found');
end;
El TsgcOpenAPIServerContext te proporciona acceso tipado a todo lo que contiene la solicitud: PathParamAsString / PathParamAsInteger para los segmentos con plantilla, QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean con valores por defecto, BodyAsString / BodyAsJSON para el cuerpo de la solicitud y HeaderValue para cualquier cabecera entrante. Para responder, utiliza los ayudantes RespondJSON(code, content) y RespondError(code, title, detail), o establece directamente Response.Code, Response.ContentType y Response.Content para un control total.
Code-First — genera la especificación desde una clase Delphi
Si prefieres escribir el contrato de la API en Delphi y dejar que la especificación se genere, decora una clase con atributos RTTI. TsgcOpenAPICodeFirstScanner recorre la clase, construye un documento JSON OpenAPI 3.0 completo y tú lo cargas en el servidor con LoadFromString. Esto requiere Delphi XE7 o posterior (para RTTI extendido).
uses
sgcHTTP_OpenAPI_Server_CodeFirst;
type
[sgcServiceContract('Task Manager API',
'A simple task management demo', '1.0.0')]
[sgcRoute('/api/v1')]
TTaskManagerService = class
public
[sgcHttpGet]
[sgcRoute('/tasks')]
[sgcSummary('List all tasks')]
[sgcTag('Tasks')]
[sgcResponse(200, 'A list of tasks')]
procedure ListTasks([sgcFromQuery] const status: string); virtual;
[sgcHttpPost]
[sgcRoute('/tasks')]
[sgcSummary('Create a new task')]
[sgcTag('Tasks')]
[sgcResponse(201, 'Task created successfully')]
procedure CreateTask([sgcFromBody] const body: string); virtual;
[sgcHttpGet]
[sgcRoute('/tasks/{taskId}')]
[sgcSummary('Get a task by ID')]
[sgcTag('Tasks')]
[sgcResponse(200, 'The requested task')]
[sgcResponse(404, 'Task not found')]
procedure GetTask([sgcFromPath][sgcRequired]
const taskId: Integer); virtual;
end;
Los cuerpos de los métodos son stubs — existen únicamente para que el compilador emita información RTTI para ellos. El trabajo real ocurre en OnRequest, despachado por el operationId que el escáner deriva del nombre de cada método (ListTasks, CreateTask, GetTask…).
Entrega la clase al escáner al inicio y carga la especificación generada en el servidor:
uses
sgcHTTP_OpenAPI_Server_CodeFirst, sgcHTTPServer_OpenAPI;
var
oScanner: TsgcOpenAPICodeFirstScanner;
oServer: TsgcHTTPServer_OpenAPI;
vSpec: string;
begin
oScanner := TsgcOpenAPICodeFirstScanner.Create;
try
vSpec := oScanner.GenerateSpec(TTaskManagerService);
finally
oScanner.Free;
end;
oServer := TsgcHTTPServer_OpenAPI.Create(nil);
oServer.LoadFromString(vSpec);
oServer.Bindings.Add.Port := 8081;
oServer.OnRequest := MyOnRequest;
oServer.Active := True;
end;
Los atributos cubren los metadatos habituales: sgcServiceContract rellena el bloque info de OpenAPI, sgcRoute establece la ruta a nivel de clase o de método, sgcHttpGet / Post / Put / Delete / Patch / Head / Options elige el verbo, sgcSummary y sgcDescription documentan la operación, sgcTag la agrupa en Swagger UI, sgcResponse(code, description) declara cada respuesta y sgcFromPath / FromQuery / FromBody / FromHeader junto con sgcRequired describen cada parámetro.
Configuración — OpenAPIOptions
Toda la configuración del lado del servidor se encuentra bajo OpenAPIOptions, agrupada en tres subopciones:
oServer.OpenAPIOptions.Endpoint.BasePath := '/api';
oServer.OpenAPIOptions.Endpoint.ServeSpec := True; // /openapi.json
oServer.OpenAPIOptions.Endpoint.ServeSwaggerUI := True; // /docs
oServer.OpenAPIOptions.CORS.Enabled := True;
oServer.OpenAPIOptions.CORS.AllowOrigins := '*';
oServer.OpenAPIOptions.CORS.AllowHeaders := 'Content-Type, Authorization';
oServer.OpenAPIOptions.CORS.AllowMethods := 'GET, POST, PUT, DELETE, PATCH, OPTIONS';
oServer.OpenAPIOptions.Validation.ValidateRequest := True;
oServer.OpenAPIOptions.Validation.ValidateRequestBody := True;
oServer.OpenAPIOptions.Validation.ValidateQueryParams := True;
oServer.OpenAPIOptions.Validation.ValidatePathParams := True;
oServer.OpenAPIOptions.Validation.ValidateRequired := True;
Con la validación activada, cada solicitud entrante se comprueba frente a los JSON Schemas declarados en la especificación antes de llegar a tu manejador — campos obligatorios, tipos, formatos, enumeraciones, rangos. Los fallos disparan el evento OnValidationError con la lista de errores y una bandera para aceptar o rechazar la solicitud.
Eventos
El componente expone seis eventos para el ciclo de vida de la solicitud:
OnBeforeRequest: se dispara antes del despacho; establece Accept := False para rechazar con un 403 Forbidden. Útil para limitación de tasa, registro o controles por ruta.
OnAuthenticate: se dispara antes del manejador principal; establece Authenticated := False para rechazar con 401 Unauthorized. Inspecciona cabeceras, cookies o parámetros de consulta para decidir.
OnValidationError: se dispara cuando la validación falla; recibe la lista de errores. Establece Continue := False para rechazar con 400 Bad Request.
OnRequest: el evento principal de despacho. Examina aOperationId, escribe la respuesta en aContext.Response y establece Handled := True.
OnAfterRequest: se dispara después de que el manejador retorne — ideal para métricas o registros de auditoría.
OnException: se dispara si una excepción no controlada se propaga fuera de tu manejador. Ajusta aResponseCode si quieres algo distinto de 500 Internal Server Error.
Demos
Con sgcOpenAPI 2026.6 se incluyen dos demos completos, ambos usando únicamente el nuevo componente independiente — sin necesidad de instalar sgcWebSockets:
- Demos/30.Server/01.CodeFirst — una API de gestión de tareas definida íntegramente con atributos sobre una clase Delphi.
- Demos/30.Server/02.SpecFirst — el clásico ejemplo Petstore, servido desde
petstore.json.
Actualización
Si actualmente usas TsgcWSServer_API_OpenAPI con sgcWebSockets, nada cambia — la clase, las propiedades y los eventos se mantienen y la implementación ahora delega en el mismo motor compartido que impulsa el nuevo componente independiente. Puedes mantener tu código existente tal cual, o migrar un formulario cada vez a TsgcHTTPServer_OpenAPI para eliminar la dependencia de sgcWebSockets.
sgcOpenAPI 2026.6 estará disponible en la página de descargas en junio.
¿Preguntas, comentarios o ayuda con la migración? Ponte en contacto — recibirás respuesta de las personas que escribieron el código.
