A próxima versão do sgcOpenAPI, versão 2026.6, prevista para junho, traz um servidor OpenAPI 3.0 que você pode hospedar sem instalar o sgcWebSockets. Dois componentes fazem isso: TsgcHTTPServer, o servidor HTTP baseado em Indy, e TsgcWSAPIServer_OpenAPI, o componente de API que você anexa a ele. Aponte o componente de API para uma especificação (ou gere uma a partir de uma classe Delphi com atributos RTTI), atribua a sua propriedade Server, inicie o servidor HTTP, e você tem uma API REST documentada com Swagger UI servido automaticamente.
A mudança principal é que o sgcOpenAPI não precisa mais do sgcWebSockets para hospedar um servidor HTTP. Os dois componentes são fornecidos, empacotados e instalados inteiramente a partir do sgcOpenAPI. Se você já usa o sgcWebSockets, o componente TsgcWSServer_API_OpenAPI que você já conhece continua funcionando sem alterações, porque é a mesma classe: os dois produtos o constroem a partir do mesmo motor.
O que você obtém
Os dois componentes trazem três coisas:
- Um servidor HTTP (baseado em Indy),
TsgcHTTPServer, com as propriedades habituaisBindings,PorteActive. - O motor OpenAPI: análise de especificação, roteamento por modelo de caminho com segmentos
{paramName}, validação JSON-Schema, CORS, tratamento de exceções. - Dois endpoints servidos automaticamente: a especificação em
/openapi.jsone o Swagger UI em/docs. Ambos estão ativos por padrão e podem ser alternados emOpenAPIOptions.Endpoint.
Início rápido — o exemplo mínimo
Isto é tudo o que você precisa para hospedar um servidor OpenAPI funcional com Swagger UI. Note que o componente de API não tem propriedade Active própria: atribuir Server é o que o anexa, e atribuir nil o desanexa enquanto o servidor HTTP continua em execução.
uses
sgcHTTP_Server, sgcWebSocket_Server_API_OpenAPI;
var
oServer: TsgcHTTPServer;
oOpenAPI: TsgcWSAPIServer_OpenAPI;
begin
oServer := TsgcHTTPServer.Create(nil);
oOpenAPI := TsgcWSAPIServer_OpenAPI.Create(nil);
try
oServer.Bindings.Add.Port := 8080;
oOpenAPI.LoadFromFile('petstore.json');
oOpenAPI.OnRequest := MyOnRequest;
oOpenAPI.Server := oServer;
oServer.Active := True;
Readln;
finally
oOpenAPI.Free;
oServer.Free;
end;
end;
Acesse http://localhost:8080/docs para o Swagger UI e http://localhost:8080/openapi.json para a especificação. Toda operação definida na especificação é roteada para o seu handler MyOnRequest com o operationId resolvido e um contexto de requisição totalmente construído.
Spec-First — carregue um arquivo OpenAPI 3.0 existente
Se você já tem um arquivo OpenAPI 3.0 em JSON (Petstore, um contrato de API interno, um esquema público que deseja simular), o spec-first é a maneira mais rápida de servi-lo. LoadFromFile lê e analisa a especificação, constrói uma tabela de rotas a partir da seção paths e compara cada requisição recebida com ela. O servidor lê JSON, então converta um contrato YAML antes, por exemplo com o sgcOpenAPI.exe.
O operationId de cada rota é a chave de despacho. Dentro de OnRequest você trata cada operação por vez:
uses
sgcHTTP_Server, sgcHTTP_OpenAPI_Server,
sgcHTTP_OpenAPI_Server_Engine, sgcWebSocket_Server_API_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;
O TsgcOpenAPIServerContext fornece acessadores tipados para tudo o que está na requisição: PathParamAsString / PathParamAsInteger para segmentos baseados em modelo, QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean com valores padrão, BodyAsString / BodyAsJSON para o corpo da requisição, e HeaderValue para qualquer cabeçalho recebido. Para responder, use os helpers RespondJSON(code, content) e RespondError(code, title, detail), ou defina Response.Code, Response.ContentType e Response.Content diretamente para controle total.
Code-First — gere a especificação a partir de uma classe Delphi
Se você preferir escrever o contrato da API em Delphi e deixar a especificação ser gerada, decore uma classe com atributos RTTI. O TsgcOpenAPICodeFirstScanner percorre a classe, constrói um documento JSON OpenAPI 3.0 completo, e você carrega isso no servidor com LoadFromString. Isto requer Delphi XE7 ou mais recente (para RTTI estendido).
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;
Os corpos dos métodos são stubs — eles existem apenas para que o compilador emita RTTI para eles. O trabalho real acontece em OnRequest, despachado pelo operationId que o scanner deriva de cada nome de método (ListTasks, CreateTask, GetTask…).
Entregue a classe ao scanner na inicialização e carregue a especificação gerada no servidor:
uses
sgcHTTP_Server, sgcHTTP_OpenAPI_Server_CodeFirst,
sgcWebSocket_Server_API_OpenAPI;
var
oScanner: TsgcOpenAPICodeFirstScanner;
oServer: TsgcHTTPServer;
oOpenAPI: TsgcWSAPIServer_OpenAPI;
vSpec: string;
begin
oScanner := TsgcOpenAPICodeFirstScanner.Create;
try
vSpec := oScanner.GenerateSpec(TTaskManagerService);
finally
oScanner.Free;
end;
oServer := TsgcHTTPServer.Create(nil);
oServer.Bindings.Add.Port := 8081;
oOpenAPI := TsgcWSAPIServer_OpenAPI.Create(nil);
oOpenAPI.LoadFromString(vSpec);
oOpenAPI.OnRequest := MyOnRequest;
oOpenAPI.Server := oServer;
oServer.Active := True;
end;
Os atributos cobrem os metadados comuns: sgcServiceContract preenche o bloco info do OpenAPI, sgcRoute define o caminho no nível da classe ou do método, sgcHttpGet / Post / Put / Delete / Patch / Head / Options escolhe o verbo, sgcSummary e sgcDescription documentam a operação, sgcTag a agrupa no Swagger UI, sgcResponse(code, description) declara cada resposta, e sgcFromPath / FromQuery / FromBody / FromHeader em conjunto com sgcRequired descrevem cada parâmetro.
Configuração — OpenAPIOptions
Toda a configuração do lado do servidor fica em OpenAPIOptions, no componente de API, agrupada em cinco subopções. Estas três reúnem as configurações do dia a dia:
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;
Com a validação ativada, toda requisição recebida é checada em relação aos JSON Schemas declarados na especificação antes de chegar ao seu handler — campos obrigatórios, tipos, formatos, enums, intervalos. Falhas disparam o evento OnValidationError com a lista de erros e um flag para aceitar ou rejeitar a requisição.
Eventos
Seis eventos cobrem o ciclo de vida da requisição:
OnBeforeRequest: dispara antes do despacho; defina Accept := False para rejeitar com 403 Forbidden. Útil para limitação de taxa, registro de logs ou controles por rota.
OnAuthenticate: dispara antes do handler principal; defina Authenticated := False para rejeitar com 401 Unauthorized. Inspecione cabeçalhos, cookies ou parâmetros de consulta para decidir.
OnValidationError: dispara quando a validação falha; recebe a lista de erros. Defina Continue := False para rejeitar com 400 Bad Request.
OnRequest: o evento principal de despacho. Observe o aOperationId, escreva a resposta em aContext.Response, defina Handled := True.
OnAfterRequest: dispara depois que o handler retorna — ideal para métricas ou log de auditoria.
OnException: dispara se uma exceção não tratada surgir do seu handler. Ajuste aResponseCode se quiser algo diferente de 500 Internal Server Error.
As duas subopções restantes têm as suas próprias: Security conduz o OnValidateAPIKey, o OnValidateBasic e o OnValidateBearer para os securitySchemes que a especificação declara, e Mock responde a uma operação sem handler usando os próprios exemplos da especificação.
Demos
Duas demos completas acompanham o sgcOpenAPI 2026.6, ambas hospedadas pela dupla independente, portanto nenhuma instalação do sgcWebSockets é necessária:
- Demos/30.Server/01.OpenAPI_Server_CodeFirst, uma API Task Manager definida inteiramente com atributos em uma classe Delphi.
- Demos/30.Server/02.OpenAPI_Server_SpecFirst, o clássico exemplo Petstore, servido a partir de
petstore.json.
Atualização
Se você atualmente usa TsgcWSServer_API_OpenAPI com sgcWebSockets, nada muda. A classe, as suas propriedades e os seus eventos são todos preservados, e a implementação delega ao motor compartilhado. O TsgcWSAPIServer_OpenAPI é o descendente publicado dessa mesma classe, então a única coisa que o sgcOpenAPI muda é de onde vem o pacote.
O sgcOpenAPI 2026.6 estará disponível na página de downloads em junho.
Dúvidas, feedback ou ajuda com a migração? Entre em contato — você receberá uma resposta das pessoas que escreveram o código.
