Function Scan_API(@API) /*********************************************************************************************************************** This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written permission from SRP Computer Solutions, Inc. Name : Scan_API Description : API logic for the Scan resource. Notes : All web APIs should include the API_SETUP insert. This will provide several useful variables: HTTPMethod - The HTTP Method (Verb) submitted by the client (e.g., GET, POST, etc.) APIURL - The URL for the API entry point (e.g., api.mysite.com/v1). FullEndpointURL - The URL submitted by the client, including query params. FullEndpointURLNoQuery - The URL submitted by the client, excluding query params. ParentURL - The URL path preceeding the current endpoint. CurrentAPI - The name of this stored procedure. Parameters : API [in] -- Web API to process. Format is [APIPattern].[HTTPMethod]: - APIPattern must follow this structure Scan[.ID.[]] - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. Examples: - Scan.POST - Scan.ID.PUT - Scan.ID.firstName.GET Response [out] -- Response to be sent back to the Controller (HTTP_MCP) or requesting procedure. Web API services do not rely upon anything being returned in the response. This is what the various services like SetResponseBody and SetResponseStatus services are for. A response value is only helpful if the developers want to use it for debug purposes. History : (Date, Initials, Notes) 07/30/19 xxx Original programmer. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $insert APP_INSERTS $insert API_SETUP $insert HTTP_INSERTS $insert SCANS_EQUATES $insert RDS_EQUATES $insert SCAN_SETUP Declare Function Scan_Services, Database_Services, QA_Services, Datetime, RDS_Services, SRP_Array, SRP_Stopwatch Declare function Logging_Services, Environment_Services Declare Subroutine Scan_Services, Database_Services, QA_Services, obj_WO_Mat_Log, SRP_Stopwatch Declare Subroutine Logging_Services LogPath = Environment_Services('GetApplicationRootPath') : '\LogFiles\ScanAPI\APIResponseTime'; //Define the directory where the log will be saved to. This happens the first time of the day that the log is written to. LogDate = Oconv(Date(), 'D4/') LogTime = Oconv(Time(), 'MTS') LoggingDTM = LogDate : ' ' : LogTime ; // Logging DTM LogFileName = LogDate[7, 4] : '-' : LogDate[1, 2] : '-' : LogDate[4, 2] : ' ScanAPIResponseTimes.csv'; //Define the file name that will get created. Headers = 'Logging DTM' : @FM : 'API' : @FM : 'ResponseTime' : @FM : 'ScanID' : @FM : 'ScanData' : @VM : 'StatusCode' ; //Define the column names in the log file, delimited by a Field Mark. objLog = Logging_Services('NewLog', LogPath, LogFileName, CRLF$, ',', Headers, '', False$, False$); //Actually creates the log. GoToAPI else // The specific resource endpoint doesn't have a API handler yet. HTTP_Services('SetResponseStatus', 200, 'This is a valid endpoint but a web API handler has not yet been created.') end Return Response OR '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Endpoint Handlers //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// API scan.POST SRP_Stopwatch('Reset') SRP_Stopwatch('Start', 'SCAN_POST_RESPONSE_TIME') ScanID = Scan_Services('CreateScansRow') If Error_Services('NoError') then StatusCode = 201 GoSub CreateHALItem end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 500, Message) end SRP_Stopwatch('Stop', 'SCAN_POST_RESPONSE_TIME') TotalPostResponseTime = SRP_Stopwatch('GetData', 'SCAN_POST_RESPONSE_TIME') LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine LogData<2> = 'SCAN.POST' LogData<3> = TotalPostResponseTime LogData<4> = ScanID LogData<5> = '' ResponseStatusCode = '' If Assigned(StatusCode) then ResponseStatusCode = StatusCode end LogData<6> = ResponseStatusCode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) end api API scan.ID.POST SRP_Stopwatch('Reset') SRP_Stopwatch('Start', 'SCAN_ID_POST_RESPONSE_TIME') ScanID = EndpointSegment // The resource will have been put into the POST string. Body = HTTP_Services('GetHTTPPostString') If Body NE '' then // The POST string will have been encoded so use percent (URL) decoding. ScanJSON = HTTP_Services('DecodePercentString', Body) Scan_Services('ProcessScanData', ScanID, ScanJSON) If Error_Services('NoError') then StatusCode = 200 GoSub CreateHALItem end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 400, Message) end end else HTTP_Services('SetResponseStatus', 400, 'JSON object is missing from the request.') end SRP_Stopwatch('Stop', 'SCAN_ID_POST_RESPONSE_TIME') TotalPostResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_POST_RESPONSE_TIME') LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine LogData<2> = 'SCAN.ID.POST' LogData<3> = TotalPostResponseTime LogData<4> = ScanID If Assigned(ScanJson) then ThisScanDataToLog = ScanJson end else ThisScanDataToLog = Body end LogData<5> = ThisScanDataToLog ResponseStatusCode = '' If Assigned(StatusCode) then ResponseStatusCode = StatusCode end LogData<6> = ResponseStatusCode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) end api API scan.ID.HEAD API scan.ID.GET SRP_Stopwatch('Reset') SRP_Stopwatch('Start', 'SCAN_ID_GET_RESPONSE_TIME') ScanID = EndpointSegment StatusCode = 200 GoSub CreateHALItem SRP_Stopwatch('Stop', 'SCAN_ID_POST_RESPONSE_TIME') TotalGetResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_GET_RESPONSE_TIME') LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine LogData<2> = 'SCAN.ID.GET' LogData<3> = TotalGetResponseTime LogData<4> = ScanID LogData<5> = '' ResponseStatusCode = '' If Assigned(StatusCode) then ResponseStatusCode = StatusCode end LogData<6> = ResponseStatusCode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) end api API scan.ID.DELETE SRP_Stopwatch('Reset') SRP_Stopwatch('Start', 'SCAN_ID_DELETE_RESPONSE_TIME') ScanID = EndpointSegment ScanRow = Database_Services('ReadDataRow', 'SCANS', ScanID) If Error_Services('NoError') then If ScanRow NE True$ then Database_Services('DeleteDataRow', 'SCANS', ScanID, True$, False$) If Error_Services('NoError') then HTTP_Services('SetResponseStatus', 200) end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 500, Message) end end else HTTP_Services('SetResponseStatus', 403, 'This scan is already accepted and cannot be deleted.') end end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 404, Message) end SRP_Stopwatch('Stop', 'SCAN_ID_DELETE_RESPONSE_TIME') TotalDeleteResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_DELETE_RESPONSE_TIME') LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine LogData<2> = 'SCAN.ID.DELETE' LogData<3> = TotalDeleteResponseTime LogData<4> = ScanID LogData<5> = '' ResponseStatusCode = '' If Assigned(StatusCode) then ResponseStatusCode = StatusCode end LogData<6> = ResponseStatusCode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) end api API scan.ID.PATCH // This is where scans are ultimately accepted for final processing. We will need to determine which type // of scan this is (i.e. Location, Pre-Epi + Load, or Unload). This will be determined by the data coming in and the // current status of the lot. For example a Location scan would only have an RDS, location code, and username. SRP_Stopwatch('Reset') SRP_Stopwatch('Start', 'SCAN_ID_PATCH_RESPONSE_TIME') ScanID = EndpointSegment SRP_Stopwatch('Start', 'IDPatchResponseTime') // First confirm that this is a valid Scan ID. jsonScan = Scan_Services('GetScansRow', ScanID, True$) If Error_Services('NoError') then // Confirm that all required data has been scanned before allowing the "accept" field to be updated. ParseResponse = SRP_JSON(objResource, 'Parse', jsonScan) If ParseResponse EQ '' then ScanAcceptable = SRP_JSON(objResource, 'GetValue', 'scan.acceptable', False$) If ScanAcceptable EQ True$ then // The resource will have been put into the POST string. Body = HTTP_Services('GetHTTPPostString') If Body NE '' then // The POST string will have been encoded so use percent (URL) decoding. ScanJSON = HTTP_Services('DecodePercentString', Body) Scan_Services('AcceptScan', ScanID, ScanJSON) If Error_Services('NoError') then StatusCode = 200 GoSub CreateHALItem end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 500, Message) end SRP_JSON(hBody, 'Release') end else HTTP_Services('SetResponseStatus', 400, 'JSON object is missing from the request.') end end else ScanNotAcceptableReason = SRP_JSON(objResource, 'GetValue', 'scan.notAcceptableReason') Error_Services('Add', ScanNotAcceptableReason) end SRP_JSON(objResource, 'Release') end else Message = 'Unable to parse the JSON scan resource.' HTTP_Services('SetResponseStatus', 400, Message) end end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 404, Message) end SRP_Stopwatch('Stop', 'SCAN_ID_PATCH_RESPONSE_TIME') TotalPatchResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_PATCH_RESPONSE_TIME') LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine LogData<2> = 'SCAN.ID.PATCH' LogData<3> = TotalPatchResponseTime LogData<4> = ScanID LogData<5> = '' ResponseStatusCode = '' If Assigned(StatusCode) then ResponseStatusCode = StatusCode end LogData<6> = ResponseStatusCode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) end api API scan.ID.PUT SRP_Stopwatch('Reset') SRP_Stopwatch('Start', 'SCAN_ID_PUT_RESPONSE_TIME') ScanID = EndpointSegment // The resource will have been put into the POST string. Body = HTTP_Services('GetHTTPPostString') If Body NE '' then // The POST string will have been encoded so use percent (URL) decoding. Body = HTTP_Services('DecodePercentString', Body) ParseResponse = SRP_JSON(hBody, 'PARSE', Body) If (ParseResponse EQ '') then ScanRow = Database_Services('ReadDataRow', 'SCANS', ScanID) If Error_Services('NoError') then // Existing scan resource is being replaced. StatusCode = 200 end else // Scan resource is being created for the first time. StatusCode = 201 end If ScanRow EQ '' then ScanRow = Date() If ScanRow EQ '' then ScanRow = Time() ScanRow = SRP_JSON(hBody, 'GetValue', 'employeeID', '') ScanRow = SRP_JSON(hBody, 'GetValue', 'toolID', '') ScanRow = SRP_JSON(hBody, 'GetValue', 'cassetteID', '') Accept = SRP_JSON(hBody, 'GetValue', 'accept', False$) If Accept EQ True$ then // Before allowing the accept field to be set to True, verify that all required data has been populated. Begin Case Case ScanRow EQ '' ; Accept = False$ Case ScanRow EQ '' ; Accept = False$ Case ScanRow EQ '' ; Accept = False$ End Case end ScanRow = Accept If ScanRow EQ True$ then ScanRow = Date() ScanRow = Time() end Database_Services('WriteDataRow', 'SCANS', ScanID, ScanRow, True$, False$, True$) If Error_Services('NoError') then GoSub CreateHALItem end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 500, Message) end SRP_JSON(hBody, 'Release') end else HTTP_Services('SetResponseStatus', 400, 'Unable to parse the scanData JSON.') end end else HTTP_Services('SetResponseStatus', 400, 'JSON object is missing from the request.') end SRP_Stopwatch('Stop', 'SCAN_ID_PUT_RESPONSE_TIME') TotalPutResponseTime = SRP_Stopwatch('GetData', 'SCAN_ID_PUT_RESPONSE_TIME') LogData = '' LogData<1> = LoggingDTM;//Defined at entry of subroutine LogData<2> = 'SCAN.ID.PUT' LogData<3> = TotalPutResponseTime LogData<4> = ScanID LogData<5> = '' ResponseStatusCode = '' If Assigned(StatusCode) then ResponseStatusCode = StatusCode end LogData<6> = ResponseStatusCode Logging_Services('AppendLog', objLog, LogData, @RM, @FM, False$) end api //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Internal GoSubs //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------------------------------------------------------- // CreateHALItem // // Creates a HAL+JSON object based on the OpenInsight data row representation of the scan. //---------------------------------------------------------------------------------------------------------------------- CreateHALItem: jsonScan = Scan_Services('ConvertMVScanToJSON', ScanID, '', FullEndpointURL) If Error_Services('NoError') then If SRP_JSON(objResource, 'Parse', jsonScan) EQ '' then lastModified = SRP_JSON(objResource, 'GetValue', 'lastModified') end else lastModified = '' end SRP_JSON(objResource, 'Release') HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) HTTP_Services('SetResponseHeaderField', 'Last-Modified', lastModified) HTTP_Services('SetResponseBody', jsonScan, False$, 'application/hal+json') If Assigned(Message) then HTTP_Services('SetResponseStatus', StatusCode, Message) end else HTTP_Services('SetResponseStatus', StatusCode) end end else Message = Error_Services('GetMessage') HTTP_Services('SetResponseStatus', 500, 'Error in the ' : CurrentAPI : ' API. Message: ': Message) end return