Skip to content
17 changes: 11 additions & 6 deletions Web API Library/AppSrc/WebApi/cBaseWebApiIterator.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,21 @@ Class cBaseWebApiIterator is a cObject
End_Procedure

//This should create a array
Function CreateResponseBodyArray String sTableName Returns Handle
Procedure CreateResponseBodyArray String sTableName Handle ByRef hoBody
//Should be augmented in iterators
Error DFERR_PROGRAM "Override this Function"
End_Function
Error DFERR_PROGRAM "Override this Procedure"
End_Procedure

//This should create a object
Function CreateResponseBodyObject String sTableName Returns Handle
Procedure CreateResponseBodyObject String sTableName Handle ByRef hoBody
//Should be augmented in iterators
Error DFERR_PROGRAM "Override this Function"
End_Function
Error DFERR_PROGRAM "Override this Procedure"
End_Procedure

Procedure CleanupHandle Handle hoObject
// Destroy the object
Error DFERR_PROGRAM "Override this Procedure"
End_Procedure

//Adds values to the response body
Procedure ModifyResponseBody Handle hoResponseBody Variant vValue String sFieldName Integer eDataType
Expand Down
43 changes: 24 additions & 19 deletions Web API Library/AppSrc/WebApi/cJSONIterator.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,34 @@ Class cJSONIterator is a cBaseWebApiIterator
Send OutputString sStringifiedJson
End_Procedure

//This should create and return a JSON array
Function CreateResponseBodyArray String sTableName Returns Handle
Handle hoJsonArray
//This should create a JSON array
Procedure CreateResponseBodyArray String sTableName Handle ByRef hoBody

//Create the JSON array and initialize it
Get Create (RefClass(cJsonObject)) to hoJsonArray
Send InitializeJsonType of hoJsonArray jsonTypeArray
If (hoBody = 0) Begin
//Create the JSON array
Get Create (RefClass(cJsonObject)) to hoBody
End

Function_Return hoJsonArray
End_Function
// Initialize the array
Send InitializeJsonType of hoBody jsonTypeArray
End_Procedure

//This should create and return a JSON Object
Function CreateResponseBodyObject String sTableName Returns Handle
Handle hoJsonObject
//This should create a JSON Object
Procedure CreateResponseBodyObject String sTableName Handle ByRef hoBody

//Create the JSON Object and initialize it
Get Create (RefClass(cJsonObject)) to hoJsonObject
Send InitializeJsonType of hoJsonObject jsonTypeObject

Function_Return hoJsonObject
End_Function
// If the handle is 0 create a json object. If its not 0 its already created we can just reinitialize it
If (hoBody = 0) Begin
//Create the JSON Object
Get Create (RefClass(cJsonObject)) to hoBody
End

Send InitializeJsonType of hoBody jsonTypeObject
End_Procedure

Procedure CleanupHandle Handle hoObject
// Destroy the object
Send Destroy of hoObject
End_Procedure

//This should append to a response body
Procedure ModifyResponseBody Handle hoResponseBody Variant vValue String sFieldName Integer eDataType
Expand All @@ -66,12 +73,10 @@ Class cJSONIterator is a cBaseWebApiIterator
//This should append a JSON object to a JSON array.
Procedure AppendToResponseArray Handle hoNestedObject Handle hoResponseArray
Send AddMember of hoResponseArray hoNestedObject
Send Destroy of hoNestedObject
End_Procedure

Procedure AppendNestedObject Handle hoNestedObject Handle hoResponseBody String sNestedObjectName
Send SetMember of hoResponseBody sNestedObjectName hoNestedObject
Send Destroy of hoNestedObject
End_Procedure

//This should parse the request body into a data type understandable by DataFlex.
Expand Down
2 changes: 1 addition & 1 deletion Web API Library/AppSrc/WebApi/cOpenApiEndpoint.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Class cOpenApiEndpoint is a cBaseRestDataset
Procedure OnHttpGet tWebApiCallContext ByRef webapicallcontext

//Just parse to the response body. The OpenApiField will do the rest
Get CreateResponseBodyObject of webapicallcontext.hoIterator "OpenApi" to webapicallcontext.hoResponseBody
Send CreateResponseBodyObject of webapicallcontext.hoIterator "OpenApi" (&webapicallcontext.hoResponseBody)
Send CurrentRecordToResponseBody webapicallcontext.hoResponseBody webapicallcontext.hoIterator
Move C_WEBAPI_OK to webapicallcontext.iStatusCode
Move "OK" to webapicallcontext.sShortStatusMessage
Expand Down
66 changes: 50 additions & 16 deletions Web API Library/AppSrc/WebApi/cOpenApiSpecification.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ Class cOpenApiSpecification is a cObject
{ Visibility = Private }
Procedure GenerateServersInfo Handle hoOpenApiSpecJson
Handle hoServersJson hoServerJson hoHttpApi
String sApiPath sRouterPath sDescription sApiRoot sServerName sSecureString
String sApiPath sRouterPath sDescription sApiRoot sServerName sSecureString sForwardedProto
Boolean bSecure
Integer iServerPort

Get GetWebApiObject to hoHttpApi
Get psPath of hoHttpApi to sApiPath
Expand All @@ -77,15 +78,25 @@ Class cOpenApiSpecification is a cObject
If (sApiRoot = "") Begin
Get ServerVariable of ghoWebServiceDispatcher "SERVER_NAME" to sServerName
Get ServerVariable of ghoWebServiceDispatcher "URL" to sApiRoot
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future see if we can check a forwarded for server name and url as well.

Get ServerVariable of ghoWebServiceDispatcher "SERVER_PORT_SECURE" to bSecure
Get ServerVariable of ghoWebServiceDispatcher "HTTP_X_FORWARDED_PROTO" to sForwardedProto

//Add http or https based on the SERVER_PORT_SECURE setting
If bSecure Begin
Move "https://" to sSecureString
// Check for reverse proxy
If (sForwardedProto <> "") Begin
Move (sForwardedProto + "://") to sSecureString
End
Else Begin
Move "http://" to sSecureString
Get ServerVariable of ghoWebServiceDispatcher "SERVER_PORT" to iServerPort
// 443 is the default secure port
Move (iServerPort = 443) to bSecure
//Add http or https based on the SERVER_PORT setting
If bSecure Begin
Move "https://" to sSecureString
End
Else Begin
Move "http://" to sSecureString
End
End

//The url contains /OpenApi since its part of the requesting url, we can take it out of the url.
Move (Replace("/OpenApi", sApiRoot, "")) to sApiRoot
Move (sSecureString + sServerName + sApiRoot) to sApiRoot
Expand Down Expand Up @@ -228,7 +239,7 @@ Class cOpenApiSpecification is a cObject

{ Visibility = Private }
Procedure ParseVerb String sCurrentVerb Handle hoEndpoint Handle hoPathsJson
Handle hoVerbJson hoResponsesJson hostatusCodeJson hoContentJson hoContentTypeJson hoSchemaJson hoTagsJson hoRequestBody hoEndpointJson
Handle hoVerbJson hoResponsesJson hostatusCodeJson hoContentJson hoContentTypeJson hoSchemaJson hoTagsJson hoRequestBody hoEndpointJson hoItemsJson
String[] asIteratorTypes
String sEndpointName sEndpointTableName sEndpointFullPath sTagName
Integer iIteratorIndex
Expand Down Expand Up @@ -313,7 +324,24 @@ Class cOpenApiSpecification is a cObject
Send ParseErrorResponse sCurrentVerb hoResponsesJson

Send SetMemberValue of hoStatusCodeJson "description" jsonTypeString (SFormat("A %1", sEndpointName))
Send SetMemberValue of hoSchemaJson "$ref" jsonTypeString (SFormat("#/components/schemas/%1", sEndpointTableName))

// GET requests should return an array.
If (sCurrentVerb = C_WEBAPI_GET) Begin
Get Create (RefClass(cJsonObject)) to hoItemsJson
Send InitializeJsonType of hoItemsJson jsonTypeObject

// schema should become type array
Send SetMemberValue of hoSchemaJson "type" jsonTypeString "array"
// $ref should be appended to the items object
Send SetMemberValue of hoItemsJson "$ref" jsonTypeString (SFormat("#/components/schemas/%1", sEndpointTableName))
Send SetMember of hoSchemaJson "items" hoItemsJson

Send Destroy of hoItemsJson
End
Else Begin
Send SetMemberValue of hoSchemaJson "$ref" jsonTypeString (SFormat("#/components/schemas/%1", sEndpointTableName))
End

Send AddMemberValue of hoTagsJson jsonTypeString sTagName

Send SetMember of hoEndpointJson (Lowercase(sCurrentVerb)) hoVerbJson
Expand Down Expand Up @@ -963,7 +991,7 @@ Class cOpenApiSpecification is a cObject
//This should add query parameters to the GET endpoint
{ Visibility = Private }
Procedure ApplyQueryParams Handle hoVerbJson Handle hoEndpoint
Integer iIndex iEnumIndex eFieldType
Integer iIndex iEnumIndex eFieldType iPrecision
Boolean bFilterable
Handle hoParametersArrayJson hoParameterJson hoSchemaJson hoEnumsJson
Handle hoKeyField
Expand Down Expand Up @@ -993,6 +1021,7 @@ Class cOpenApiSpecification is a cObject
//Get all needed info from the field
Get FieldName of hoExposedDataObjects[iIndex] to sFieldName
Get FieldType of hoExposedDataObjects[iIndex] to eFieldType
Get piPrecision of hoExposedDataObjects[iIndex] to iPrecision
Get FieldValidationTable of hoExposedDataObjects[iIndex] to avValidationTable

//Set the json members
Expand All @@ -1005,7 +1034,7 @@ Class cOpenApiSpecification is a cObject
Move "" to sFieldFormat

//Determine the field type and formatting
Send FieldTypeToOpenApiType eFieldType (&sFieldType) (&sFieldFormat)
Send FieldTypeToOpenApiType eFieldType (&sFieldType) (&sFieldFormat) iPrecision

Send SetMemberValue of hoSchemaJson "type" jsonTypeString sFieldType

Expand Down Expand Up @@ -1046,6 +1075,7 @@ Class cOpenApiSpecification is a cObject
Handle hoKeyfield
String sFieldName sFieldType sFieldFormat
Integer eFieldType
Integer iPrecision

Get RetrieveKeyField of hoEndpoint to hoKeyField
//Just return if there is no keyfield
Expand All @@ -1065,13 +1095,14 @@ Class cOpenApiSpecification is a cObject

//Get the field name of the unique key
Get FieldType of hoKeyField to eFieldType
Get piPrecision of hoKeyfield to iPrecision

//Set the path parameter values
Send SetMemberValue of hoParameterJson "in" jsonTypeString "path"
Send SetMemberValue of hoParameterJson "name" jsonTypeString "Id"
Send SetMemberValue of hoParameterJson "required" jsonTypeBoolean True

Send FieldTypeToOpenApiType eFieldType (&sFieldType) (&sFieldFormat)
Send FieldTypeToOpenApiType eFieldType (&sFieldType) (&sFieldFormat) iPrecision

Send SetMemberValue of hoSchemaJson "type" jsonTypeString sFieldType

Expand All @@ -1088,7 +1119,7 @@ Class cOpenApiSpecification is a cObject
//This will parse the fields defined inside of a dataset
{ Visibility = Private }
Procedure FieldToOpenApi Handle hoField Handle hoPropertiesJson
Integer eFieldType iChildCount iIndex
Integer eFieldType iChildCount iIndex iPrecision
String sFieldName sFieldType sFieldHelp sNestedSchemaName sFieldFormat
Handle hoNestedPropertiesObject hoNestedSchema hoNestedSchemaProperties hoForeignSchemaChild hoItems
Handle[] hoNestedFields
Expand Down Expand Up @@ -1157,6 +1188,7 @@ Class cOpenApiSpecification is a cObject
Get FieldName of hoField to sFieldName
Get FieldType of hoField to eFieldType
Get FieldHelp of hoField to sFieldHelp
Get piPrecision of hoField to iPrecision
Get pbReadOnly of hoField to bReadOnly
Get pbWriteOnly of hoField to bWriteOnly
Get FieldValidationTable of hoField to avValidationTable
Expand All @@ -1165,7 +1197,7 @@ Class cOpenApiSpecification is a cObject
Send InitializeJsonType of hoNestedPropertiesObject jsonTypeObject

//Determine the type for the OpenApi spec
Send FieldTypeToOpenApiType eFieldType (&sFieldType) (&sFieldFormat)
Send FieldTypeToOpenApiType eFieldType (&sFieldType) (&sFieldFormat) iPrecision

Send SetMemberValue of hoNestedPropertiesObject "type" jsonTypeString sFieldType

Expand Down Expand Up @@ -1282,7 +1314,7 @@ Class cOpenApiSpecification is a cObject

//Helper function to map df field types to the ones used in the OpenApi specification
{ Visibility = Private }
Procedure FieldTypeToOpenApiType Integer eDataflexFieldType String ByRef sFieldType String ByRef sFieldFormat
Procedure FieldTypeToOpenApiType Integer eDataflexFieldType String ByRef sFieldType String ByRef sFieldFormat Integer iPrecision

If (eDataflexFieldType = DF_ASCII or eDataflexFieldType = DF_TEXT) Begin
Move "string" to sFieldType
Expand All @@ -1299,10 +1331,12 @@ Class cOpenApiSpecification is a cObject
Move "string" to sFieldType
Move "binary" to sFieldFormat
End
Else If (eDataflexFieldType = DF_BCD) Begin
Else If (eDataflexFieldType = DF_BCD and iPrecision = 0) Begin
Move "integer" to sFieldType
End

Else If (eDataflexFieldType = DF_BCD) Begin
Move "number" to sFieldType
End
End_Procedure

{ Visibility = Private }
Expand Down
48 changes: 25 additions & 23 deletions Web API Library/AppSrc/WebApi/cRestChildCollection.pkg
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Class cRestChildCollection is a cObject

Property Boolean pbReadOnly True
Property Integer piLimitResult 0
Property Integer piFindIndex 1

End_Procedure

Expand All @@ -35,23 +36,24 @@ Class cRestChildCollection is a cObject
*/
Procedure AppendToBody Handle hoResponseBody Handle hoIterator
Handle hoNestedArray hoNestedObject hoChild hoServer
Integer iChildCount iIndex iLimit iRecordsRetrieved
Integer iChildCount iIndex iLimit iRecordsRetrieved iFindIndex
String sNodeName

Get Server to hoServer
Get SchemaName to sNodeName
Get Child_Count to iChildCount
Get piLimitResult to iLimit
Get piFindIndex to iFindIndex

//Create nested object
Get CreateResponseBodyArray of hoIterator sNodeName to hoNestedArray
Send CreateResponseBodyArray of hoIterator sNodeName (&hoNestedArray)

//Start finding the child records
Send Find of hoServer FIRST_RECORD 1
Send Find of hoServer FIRST_RECORD iFindIndex

While ( (Found) and not(Err) and ((iLimit = 0) or (iLimit > 0 and iRecordsRetrieved < iLimit)) )
//When we find a record create a new nested object
Get CreateResponseBodyObject of hoIterator sNodeName to hoNestedObject
Send CreateResponseBodyObject of hoIterator sNodeName (&hoNestedObject)

//Loop through this objects children and append their values to the nested object
For iIndex from 0 to (iChildCount - 1)
Expand All @@ -64,31 +66,14 @@ Class cRestChildCollection is a cObject

Increment iRecordsRetrieved
//Keep finding child records
Send Find of hoServer NEXT_RECORD 1
Send Find of hoServer NEXT_RECORD iFindIndex
Loop

Send AppendNestedObject of hoIterator hoNestedArray hoResponseBody sNodeName
End_Procedure

Function SchemaName Returns String
Integer iFile
String sTableName
Handle hoServer

Get psNodeName to sTableName

//If the node name was not manually set default to the name of the table
If (sTableName <> "") Begin
Function_Return sTableName
End

Get Server to hoServer

Get Main_File of hoServer to iFile

Get_Attribute DF_FILE_LOGICAL_NAME of iFile to sTableName

Function_Return sTableName
Function_Return (psNodeName(Self))
End_Function

Function FieldName Returns String
Expand All @@ -103,4 +88,21 @@ Class cRestChildCollection is a cObject
Function IsRequired Returns Boolean
Function_Return False
End_Function

Procedure AfterAttachDDO
Integer iFile
Handle hoServer
String sTableName

Get Server to hoServer
Get Main_File of hoServer to iFile

If (hoServer = 0 and iFile = 0) ;
Procedure_Return

If (psNodeName(Self) = "") Begin
Get_Attribute DF_FILE_LOGICAL_NAME of iFile to sTableName
Set psNodeName to sTableName
End
End_Procedure
End_Class
Loading