Function Picture_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 : Picture_API Description : API logic for the Picture 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 [.ID.[]] - HTTPMethod can be any valid HTTP method, e.g., GET, POST, PUT, DELETE, etc. Examples: - Picture.POST - Picture.ID.PUT - Picture.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) 11/19/18 dmb Original programmer. 01/23/20 dmb [SRPFW-296] Add matching HEAD APIs for all GET APIs. ***********************************************************************************************************************/ #pragma precomp SRP_PreCompiler $insert APP_INSERTS $insert API_SETUP $insert HTTP_INSERTS $insert CONTACTS_EQUATES PictureFolder = '\WebAppData\ContactPictures\' GoToAPI else // The specific resource endpoint doesn't have a API handler yet. HTTP_Services('SetResponseStatus', 204, 'This is a valid endpoint but a web API handler has not yet been created.') end Return Response OR '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Endpoint Handlers //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// API picture.GET API picture.HEAD // Get the picture's physical file path from the CONTACT database row. KeyID = ParentSegment PicturePath = Drive() : HTTP_Resource_Services('GetColumnValues', 'CONTACTS', 'picture', KeyID) If PicturePath NE '' then // Verify the picture actually exists. If Dir(PicturePath) NE '' then // Get the image extension. ImageExt = PicturePath[-1, 'B.'] If ImageExt _EQC 'jpg' then ImageExt = 'jpeg' // Get the best content type that matches the client's and server's ability. ContentType = HTTP_Services('GetBestContentNegotiation', 'Accept', 'text/plain' : @FM : 'image/' : ImageExt) If ContentType NE '' then OSRead PictureBinary from PicturePath then Begin Case Case ContentType _EQC 'text/plain' PictureBody = SRP_Encode(PictureBinary, 'BASE64') PictureBody = 'data:' : 'image/' : ImageExt : ';base64,' : PictureBody HTTP_Services('SetResponseHeaderField', 'Content-Encoding', 'base64') HTTP_Services('SetResponseBody', PictureBody, False$, 'text/plain') Case ContentType[1, 6] _EQC 'image/' HTTP_Services('SetResponseBody', PictureBinary, True$, ContentType) End Case end else HTTP_Services('SetResponseError', '', '', 404, 'Picture for contact ' : KeyID : ' does not exist.', FullEndpointURL) end end end else HTTP_Services('SetResponseError', '', '', 404, 'Picture for contact ' : KeyID : ' does not exist.', FullEndpointURL) end end else HTTP_Services('SetResponseError', '', '', 404, 'Picture for contact ' : KeyID : ' does not exist.', FullEndpointURL) end end api API picture.PUT KeyID = ParentSegment TableName = 'CONTACTS' ContentType = HTTP_Services('GetHTTPContentType') If ContentType EQ '' OR ContentType _EQC 'text/plain' then Open TableName to hTable then Lock hTable, KeyID then ResponseStatus = 200 ; // Updating an existing resource. Read DataRow from hTable, KeyID else DataRow = '' ResponseStatus = 201 ; // Creating a new resource. end // A URI scheme of the Base64 encoded image will be in the Data variable. HTTPPostString = HTTP_Services('GetHTTPPostString') HTTPPostString = HTTP_Services('DecodePercentString', HTTPPostString) Scheme = HTTPPostString[1, 'F:'] If Scheme _EQC 'data' then MediaType = HTTPPostString[Col2() + 1, 'F;'] ; // Should be "image/png" or "image/jpg" Encoding = HTTPPostString[Col2() + 1, 'F,'] ; // Should be "base64" EncodedData = HTTPPostString[Col2() + 1, Len(HTTPPostString)] ; // Should be the actual Base64 encoded content. DecodedData = SRP_Decode(EncodedData, 'BASE64') FileType = MediaType[-1, 'B/'] FileName = KeyID : '.' : FileType FilePath = Drive() : PictureFolder : FileName Status() = 0 OSWrite DecodedData to FilePath StatusCode = Status() If StatusCode then Begin Case Case StatusCode EQ 1 ; Error = 'Bad OS filename. Code: ' : StatusCode Case StatusCode EQ 2 ; Error = 'Access denied by operating system. Code: ' : StatusCode Case StatusCode EQ 3 ; Error = 'Disk or directory full. Code: ' : StatusCode Case StatusCode EQ 4 ; Error = 'File does not exist. Code: ' : StatusCode Case StatusCode EQ 5 ; Error = 'Unknown error. Code: ' : StatusCode Case StatusCode EQ 6 ; Error = 'Attempt to write to read-only file. Code: ' : StatusCode Case Otherwise$ ; Error = 'Unknown error. Code: ' : StatusCode End Case HTTP_Services('SetResponseError', '', '', 501, Error, FullEndpointURL) end else DataRow = PictureFolder : FileName Write DataRow to hTable, KeyID then HTTP_Services('SetResponseStatus', ResponseStatus) HTTP_Services('SetResponseHeaderField', 'Content-Location', FullEndpointURL) end else HTTP_Services('SetResponseError', '', '', 500, 'Error writing ' : KeyID : ' to the ' : TableName : ' table.', FullEndpointURL) end end end else HTTP_Services('SetResponseError', '', '', 415, '', FullEndpointURL) end Unlock hTable, KeyID else Null end else HTTP_Services('SetResponseError', '', '', 423, KeyID : ' is currently locked.', FullEndpointURL) end end else HTTP_Services('SetResponseError', '', '', 500, 'Error opening the ' : TableName : ' table.', FullEndpointURL) end end else HTTP_Services('SetResponseError', '', '', 415, 'Content-Type ' : ContentType : ' is not supported. Must specify "text/plain" or nothing.', FullEndpointURL) end end api