{******************************************************************************} { } { Delphi SwagDoc Library } { Copyright (c) 2018 Marcelo Jaloto } { https://github.com/marcelojaloto/SwagDoc } { } {******************************************************************************} { } { Licensed under the Apache License, Version 2.0 (the "License"); } { you may not use this file except in compliance with the License. } { You may obtain a copy of the License at } { } { http://www.apache.org/licenses/LICENSE-2.0 } { } { Unless required by applicable law or agreed to in writing, software } { distributed under the License is distributed on an "AS IS" BASIS, } { WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. } { See the License for the specific language governing permissions and } { limitations under the License. } { } {******************************************************************************} unit Swag.Doc.Path; interface uses WinApi.Windows, System.Classes, System.Generics.Collections, System.RegularExpressions, System.JSON, Swag.Common.Types, Swag.Doc.Path.Operation.RequestParameter, Swag.Doc.Path.Operation.Response, Swag.Doc.Path.Operation; type /// /// Holds the relative paths to the individual endpoints. /// The path is appended to the basePath in order to construct the full URL. /// The Paths may be empty, due to ACL constraints. /// TSwagPath = class(TObject) private fOperations: TObjectList; fUri: string; fParameters: TObjectList; procedure LoadResponse(pOperation: TSwagPathOperation; pJsonResponse: TJSONObject); procedure LoadOperationScopedParameters(pOperation: TSwagPathOperation; pJsonRequestParams: TJSONArray); procedure LoadPathScopedParameters(pJsonRequestParams: TJSONArray); procedure LoadTags(pOperation: TSwagPathOperation; pJsonTags: TJSONArray); procedure LoadProduces(pOperation: TSwagPathOperation; pJsonProduces: TJSONArray); procedure LoadConsumes(pOperation: TSwagPathOperation; pJsonConsumes: TJSONArray); function GenerateParametersJsonObject: TJSONArray; public constructor Create; reintroduce; destructor Destroy; override; function GenerateJsonObject: TJSONObject; procedure Load(pJson: TJSONObject); /// /// A relative path to an individual endpoint. The field name MUST begin with a slash. /// The path is appended to the basePath in order to construct the full URL. Path templating is allowed. /// property Uri: string read fUri write fUri; /// /// Describes a single API operation on a path. /// property Operations: TObjectList read fOperations; property Parameters: TObjectList read fParameters; end; implementation uses System.SysUtils, Swag.Common.Types.Helpers; { TSwagPath } constructor TSwagPath.Create; begin inherited Create; fOperations := TObjectList.Create; fParameters := TObjectList.Create; end; destructor TSwagPath.Destroy; begin FreeAndNil(fOperations); FreeAndNil(fParameters); inherited Destroy; end; function TSwagPath.GenerateParametersJsonObject: TJSONArray; var vIndex: Integer; begin Result := TJSONArray.Create; for vIndex := 0 to fParameters.Count - 1 do begin Result.Add(fParameters[vIndex].GenerateJsonObject); end; end; function TSwagPath.GenerateJsonObject: TJSONObject; var vIndex: integer; begin Result := TJsonObject.Create; if fParameters.Count > 0 then Result.AddPair('parameters', GenerateParametersJsonObject); for vIndex := 0 to fOperations.Count -1 do Result.AddPair(fOperations.Items[vIndex].OperationToString, fOperations.Items[vIndex].GenerateJsonObject); end; procedure TSwagPath.Load(pJson: TJSONObject); var vIndex: Integer; vOperation: TSwagPathOperation; vOperationJson: TJSONObject; vOperationExternalDocs: TJSONObject; vOperationName: string; begin if not Assigned(pJson) then Exit; for vIndex := 0 to pJson.Count - 1 do begin vOperation := TSwagPathOperation.Create; vOperationName := pJson.Pairs[vIndex].JsonString.Value; if vOperationName = 'parameters' then begin LoadPathScopedParameters(pJson.Pairs[vIndex].JsonValue as TJSONArray); continue; end; if TRegEx.IsMatch(vOperationName, '(^x-)') then begin // This is an extension value - ignore continue; end; if not (pJson.Pairs[vIndex].JsonValue is TJSONObject) then begin // This shouldn't happen - although it may be valid in openapi documents continue; end; vOperationJson := pJson.Pairs[vIndex].JsonValue as TJSONObject; if Assigned(vOperationJson.Values['description']) then vOperation.Description := vOperationJson.Values['description'].Value; if Assigned(vOperationJson.Values['summary']) then vOperation.Summary := vOperationJson.Values['summary'].Value; vOperationExternalDocs := vOperationJson.Values['externalDocs'] as TJSONObject; if Assigned(vOperationExternalDocs) then begin if Assigned(vOperationExternalDocs.Values['url']) then vOperation.ExternalDocs.Url := vOperationExternalDocs.Values['url'].Value; if Assigned(vOperationExternalDocs.Values['description'])then vOperation.ExternalDocs.Description := vOperationExternalDocs.Values['description'].Value; end; vOperation.Operation.ToType(pJson.Pairs[vIndex].JsonString.Value); if Assigned(vOperationJson.Values['operationId']) then vOperation.OperationId := vOperationJson.Values['operationId'].Value; if Assigned(vOperationJson.Values['deprecated']) then vOperation.Deprecated := (vOperationJson.Values['deprecated'] as TJSONBool).AsBoolean; LoadTags(vOperation, vOperationJson.Values['tags'] as TJSONArray); LoadProduces(vOperation, vOperationJson.Values['produces'] as TJSONArray); LoadConsumes(vOperation, vOperationJson.Values['consumes'] as TJSONArray); LoadOperationScopedParameters(vOperation, vOperationJson.Values['parameters'] as TJSONArray); LoadResponse(vOperation, vOperationJson.Values['responses'] as TJSONObject); fOperations.Add(vOperation); end; end; procedure TSwagPath.LoadTags(pOperation: TSwagPathOperation; pJsonTags: TJSONArray); var vIndex: Integer; vTag: string; begin if not Assigned(pJsonTags) then Exit; for vIndex := 0 to pJsonTags.Count - 1 do begin vTag := pJsonTags.Items[vIndex].Value; pOperation.Tags.Add(vTag); end; end; procedure TSwagPath.LoadPathScopedParameters(pJsonRequestParams: TJSONArray); var vIndex: Integer; vRequestParam: TSwagRequestParameter; begin if not Assigned(pJsonRequestParams) then Exit; for vIndex := 0 to pJsonRequestParams.Count - 1 do begin vRequestParam := TSwagRequestParameter.Create; vRequestParam.Load(pJsonRequestParams.Items[vIndex] as TJSONObject); Parameters.Add(vRequestParam); end; end; procedure TSwagPath.LoadOperationScopedParameters(pOperation: TSwagPathOperation; pJsonRequestParams: TJSONArray); var vIndex: Integer; vRequestParam: TSwagRequestParameter; begin if not Assigned(pJsonRequestParams) then Exit; for vIndex := 0 to pJsonRequestParams.Count - 1 do begin vRequestParam := TSwagRequestParameter.Create; vRequestParam.Load(pJsonRequestParams.Items[vIndex] as TJSONObject); pOperation.Parameters.Add(vRequestParam); end; end; procedure TSwagPath.LoadProduces(pOperation: TSwagPathOperation; pJsonProduces: TJSONArray); var vIndex: Integer; vProduces: string; begin if not Assigned(pJsonProduces) then Exit; for vIndex := 0 to pJsonProduces.Count - 1 do begin vProduces := pJsonProduces.Items[vIndex].Value; pOperation.Produces.Add(vProduces); end; end; procedure TSwagPath.LoadConsumes(pOperation: TSwagPathOperation; pJsonConsumes: TJSONArray); var vIndex: Integer; vConsumes: string; begin if not Assigned(pJsonConsumes) then Exit; for vIndex := 0 to pJsonConsumes.Count - 1 do begin vConsumes := pJsonConsumes.Items[vIndex].Value; pOperation.Consumes.Add(vConsumes); end; end; procedure TSwagPath.LoadResponse(pOperation: TSwagPathOperation; pJsonResponse: TJSONObject); var vIndex: Integer; vResponse: TSwagResponse; begin if not Assigned(pJsonResponse) then Exit; for vIndex := 0 to pJsonResponse.Count - 1 do begin vResponse := TSwagResponse.Create; vResponse.StatusCode := pJsonResponse.Pairs[vIndex].JsonString.Value; vResponse.Load(pJsonResponse.Pairs[vIndex].JsonValue as TJSONObject); pOperation.Responses.Add(vResponse.StatusCode, vResponse); end; end; end.