O sgcOpenAPI 2026.9.0 é a maior versão que o produto já teve. A versão anterior lidava com o formato de especificação que a maioria dos tutoriais mostra, e degradava silenciosamente em todo o resto. Esta passou pelo parser recurso por recurso, confrontando-o com as especificações OpenAPI 3.0, 3.1 e 3.2 e com documentos reais publicados, e o resultado são 9 recursos novos, 26 bugs corrigidos e 5 mudanças incompatíveis deliberadas.
Em resumo: o cliente gerado agora é correto para especificações que antes produziam código que não compilava, ou pior, código que compilava e chamava a URL errada.
O Parser Agora Diz o Que Não Conseguiu Fazer
O parser antigo tinha uma única forma de relatar problemas, que era levantar uma exceção, e uma única forma de tratar todo o resto, que era seguir em frente silenciosamente. Uma operação que ele não conseguia gerar simplesmente não aparecia na saída, e você descobria isso ao procurar por um método que não estava lá.
Todo documento agora retorna com uma lista Warnings. Um membro openapi ou info ausente, um membro com o tipo JSON errado, uma operação que não pôde ser gerada, uma referência de path item não resolvida e uma palavra-chave de JSON Schema que é lida mas ainda não é aplicada ficam todos registrados ali. A lista é limpa a cada leitura, portanto o que você obtém pertence ao documento que acabou de ser analisado.
uses
sgcOpenAPI_Classes, sgcOpenAPI_Parser_Client_Pascal;
var
oParser: TsgcOpenAPI_Parser_Client_Pascal;
i: Integer;
begin
oParser := TsgcOpenAPI_Parser_Client_Pascal.Create;
Try
oParser.OpenAPIClassName := 'TPetStoreClient';
oParser.OpenAPINamespace := 'PetStore';
oParser.OutputFileName := 'PetStoreClient.pas';
oParser.ReadFromFile('petstore.json');
for i := 0 to oParser.Warnings.Count - 1 do
Memo1.Lines.Add('warning: ' + oParser.Warnings[i]);
oParser.SaveToFile('PetStoreClient.pas');
Finally
oParser.Free;
End;
end;
Defina OutputFileName antes de salvar. Uma unit Pascal só compila quando o nome declarado coincide com o nome base do seu arquivo, e o gerador costumava nomear a unit conforme o documento de entrada, de modo que gerar MyClient.pas a partir de petstore.json produzia uma unit chamada petstore que não compilava. Agora o nome de saída prevalece.
Ele Sabe Qual Versão Está Lendo
OpenAPI 3.0 e 3.1 divergem em palavras-chave que compartilham o mesmo nome, e o parser antigo tratava todo documento como 3.0. O caso mais claro é exclusiveMinimum, que é um modificador booleano de minimum no 3.0 e um número por si só no 3.1. Ler um como se fosse o outro resulta em um limite errado.
A versão agora é interpretada como um dialeto, exposto em Dialect, DialectMajor e DialectMinor, e cada palavra-chave que difere é lida da forma que a sua própria versão exige.
oParser.ReadFromFile('api.yaml');
case oParser.Dialect of
oapiDialect30: ShowMessage('OpenAPI 3.0');
oapiDialect31: ShowMessage('OpenAPI 3.1');
oapiDialect32: ShowMessage('OpenAPI 3.2');
end;
Além disso, o 3.1 traz webhooks, jsonSchemaDialect e components.pathItems, o identifier da licença, o esquema de segurança mutualTLS, um tipo declarado como um array, por exemplo ["string","null"], e um schema declarado como um booleano simples. Todos eles são suportados. As palavras-chave do JSON Schema 2020-12 sobre as quais o gerador de código ainda não atua são lidas para o modelo e informadas através de Warnings, de modo que a lacuna fica visível em vez de invisível.
Do 3.2, o parser suporta a operação query e o mapa additionalOperations. Um path que declare qualquer um dos dois agora gera os métodos correspondentes, enviados como um POST com um cabeçalho X-HTTP-Method-Override.
Parâmetros no Nível do Path
Esta é a correção que a maioria dos usuários vai sentir. A especificação permite declarar um parâmetro uma única vez no path item em vez de repeti-lo em cada operação abaixo dele, e esse é o estilo que a especificação recomenda e o estilo que a maioria dos documentos públicos usa. O parser antigo lia esses parâmetros e depois os descartava.
O método gerado não recebia argumento algum, e a requisição saía com o placeholder ainda na URL, literalmente /pets/{petId}. Parecia um cliente funcional até a primeira chamada retornar um 404.
Schemas Que Compõem
A composição era a parte mais fraca do parser antigo, e cada ramo dela estava errado de uma forma diferente. allOf mantinha apenas o último de vários schemas base e descartava os membros dos demais. oneOf fundia todos os ramos em uma única classe, o que produzia campos duplicados. anyOf não era tratado de forma alguma e resolvia para uma string. Um schema que declarasse ao mesmo tempo properties e additionalProperties perdia todas as suas propriedades.
Os quatro agora geram o que o documento descreve. Um schema de objeto inline também ganha a sua própria classe em vez de degradar para uma string, e items é lido como um schema completo, de modo que um array de objetos inline, um array de enums e um array aninhado geram, cada um, o tipo correto.
Enums Que Carregam o Valor Que o Servidor Espera
As tabelas de enum geradas continham o identificador Pascal sanitizado em vez do valor transmitido, de modo que allow-all saía como allowall e json-file como jsonfile. Toda requisição construída a partir de um desses enums era rejeitada.
As tabelas agora carregam o valor real, a ordem de declaração da especificação é preservada, os enums de inteiros também ganham uma tabela, e um membro Unknown adicional é gerado para que um valor que o servidor acrescente mais tarde não seja decodificado silenciosamente como o primeiro membro da lista.
Os nomes de propriedades recebem o mesmo tratamento na direção oposta. Uma propriedade de schema com o nome de uma palavra reservada do Delphi, como property, class, string ou function, ou duas propriedades que diferem apenas por maiúsculas e minúsculas, como Name e name, produziam uma unit que não compilava. A propriedade agora é renomeada e o nome transmitido é preservado com um atributo JSONName, de modo que a serialização continua correspondendo ao documento.
Respostas, Inclusive as Que Você Declara Uma Só Vez
A resposta default e as respostas por faixa 2XX, 4XX e 5XX eram descartadas silenciosamente. Uma API que declara os seus erros apenas através de default, o que é comum, gerava um cliente sem nenhum erro tipado. Agora elas são lidas. Quando várias respostas de sucesso são declaradas, a menor delas é usada, e application/json é preferido quando uma operação oferece vários media types.
Parâmetros na Transmissão
O cliente gerado agora suporta parâmetros de cookie e as regras completas de serialização de parâmetros do OpenAPI: matrix, label, simple, form, spaceDelimited, pipeDelimited e deepObject, cada uma com explode e allowReserved. Os novos métodos AddArray e AddObject constroem os valores estruturados manualmente quando você precisar.
// query parameters built with the serialization style the document declares
oRequest.AddArray('tags', ['dog', 'cat'], True); // explode
oRequest.AddObject('filter', ['color', 'red', 'size', 'M']);
Referências Externas
Uma especificação dividida em vários arquivos mal funcionava. Uma referência com um fragmento JSON Pointer, como ./common.yaml#/components/schemas/Error, não podia ser resolvida. Dois arquivos que se referenciassem mutuamente travavam o parser. Uma referência relativa dentro de um subdocumento era resolvida em relação ao documento raiz em vez do seu próprio arquivo. Dois arquivos externos com o mesmo nome base sobrescreviam um ao outro, e podiam substituir um schema pertencente ao documento principal. E uma cadeia de referências era seguida por exatamente um passo.
Tudo isso está corrigido, e uma coisa foi restringida deliberadamente: antes, uma referência externa podia ler qualquer arquivo da máquina, inclusive ../../../credentials.json, e copiar o conteúdo para a unit gerada. As referências externas agora ficam confinadas ao diretório do documento principal. Quando um layout realmente precisa sair dele, o confinamento é liberado explicitamente.
uses
sgcOpenAPI_Bundle;
begin
// off by default: references may not leave the folder of the main document
sgcOpenAPIAllowRefsOutsideRoot := True;
end;
Arquivos Que Não São Bem UTF-8
A RFC 8259 diz que um documento JSON é UTF-8, e muitas especificações publicadas não são. Um arquivo com byte order mark era rejeitado com um erro de UTF-8 assim que continha qualquer caractere fora do ASCII, e o texto em chinês ou japonês era substituído silenciosamente por pontos de interrogação.
Um documento que não é UTF-8 válido agora é lido como Windows-1252 com um aviso registrado, em vez de falhar. Um arquivo UTF-16 com byte order mark é lido corretamente. O arquivo gerado é escrito com uma codificação explícita, e um caractere que a codificação de destino não consegue representar é informado em vez de virar silenciosamente um ponto de interrogação.
Uma Linha de Comando Que Você Pode Colocar em um Script de Build
A linha de comando agora define um código de saída: 0 em caso de sucesso, e de 1 a 7 para as diferentes falhas, de modo que um passo do build consegue saber se a geração funcionou. As mensagens de erro sempre vão para a saída de erro padrão, e a opção -l agora serve apenas para o log de progresso.
sgcOpenAPI -i petstore.json -o PetStoreClient.pas -c TPetStoreClient
if errorlevel 1 (
echo OpenAPI generation failed with exit code %errorlevel%
exit /b %errorlevel%
)
Três bugs da linha de comando foram junto. A opção documentada -output escrevia a unit em um arquivo chamado utput no diretório atual, e como as mensagens eram suprimidas a execução ainda parecia bem-sucedida. Nada acontecia quando a ferramenta era executada sem console associado, que é exatamente o caso em uma tarefa agendada ou em um agente de build, e um redirecionamento de saída existente era descartado. E -h imprimia um erro de licença em vez do texto de uso em uma máquina que não estava ativada, um valor inválido para -m ou -a era aceito silenciosamente, e uma opção desconhecida era ignorada.
Novidade nesta versão, -r (ou -remote) converte um documento YAML ou Swagger 2.0 através do conversor público em converter.swagger.io. Está desativado por padrão, porque envia o seu documento a terceiros, então é algo que você ativa de forma consciente.
A própria conversão de Swagger 2.0 estava quebrada de duas formas que vale a pena citar. Todo número virava uma string, de modo que um default numérico produzia uma unit que não compilava e o documento convertido não era OpenAPI 3.0 válido. E um discriminator do Swagger 2.0, que ali é uma string simples, abortava toda a análise com um typecast inválido.
Mudanças Incompatíveis
Cinco mudanças exigem uma decisão sua, e não apenas uma atualização.
Os clientes gerados agora verificam o certificado do servidor. Antes não verificavam, o que significa que aceitavam qualquer certificado, inclusive um apresentado por um atacante no meio do caminho. Para alcançar um endpoint autoassinado ou de teste, desative a verificação deliberadamente.
oClient.TLSOptions.VerifyCertificate := False; // test endpoints only
// certificates are trusted through the OpenSSL default paths, so a machine
// with no certificate store configured needs an explicit root
oClient.TLSOptions.RootCertFile := 'cacert.pem';
O corpo da requisição é UTF-8. Como a RFC 8259 exige. Uma classe agora serializa uma string vazia como "field": "" em vez de omiti-la. Os valores nulos são controlados separadamente.
oClient.JSONIgnoreEmptyStrings := True; // previous output
oClient.JSONIgnoreNullValues := True; // default
Uma resposta não libera mais um ResponseStream fornecido por você. Defina OwnsResponseStream como True para o comportamento antigo. Liberar o cliente de dentro do seu próprio manipulador OnResponse, OnError ou OnCancel agora levanta um erro claro em vez de travar.
O valor de uma opção de linha de comando deve ser escrito como -name value ou -name:value. A forma anexada sem separador, como -x"GET /pets", não é mais aceita. Essa forma também era o que fazia -x coincidir com outras opções começadas por x, como -xml.
Um parâmetro declarado como um array é gerado como um array. Antes era gerado como uma string, portanto a assinatura do método gerado muda para essas operações.
Todo o Resto
As correções restantes são do tipo que você só percebe quando elas mordem. Um membro com um tipo JSON inesperado, por exemplo "properties": [], abortava a análise com um typecast inválido em vez de ser ignorado. Um schema do tipo integer sem default recebia um default de 0, e um enum de valor único era tratado como uma constante, o que removia por completo o parâmetro do método gerado. Ler o mesmo documento duas vezes duplicava cada path, tag, server e schema. Uma extensão de especificação como x-tagGroups colocada entre os paths era lida como se fosse um path. enum, required e tags eram analisados com um utilitário de texto separado por vírgulas, de modo que um valor contendo uma vírgula ou um escape JSON era dividido ou corrompido. Um requisito de segurança que listasse vários esquemas mantinha apenas o primeiro, perdendo a exigência de que todos eles fossem satisfeitos. info.contact e info.license nunca eram lidos, por causa de um teste que jamais poderia ser verdadeiro. Uma URL de servidor com várias variáveis substituía o valor errado e podia levantar um erro de índice de lista. Empacotar uma especificação sobrescrevia o arquivo de entrada sem backup e sem mensagem, e apagava todos os apóstrofos tipográficos do documento. E uma especificação armazenada em um caminho que contivesse um espaço, como C:\My Specs\, não conseguia resolver as suas referências externas.
Como Obter
O sgcOpenAPI 2026.9.0 já está disponível, com código-fonte completo e um ano de atualizações. Suporta do Delphi 7 ao Delphi 13 Florence e as versões correspondentes do C++ Builder.
Página do produto · Baixar a versão de teste · Changelog
Dúvidas ou comentários? Entre em contato, você receberá uma resposta das pessoas que escreveram o código.
