16 hours ago16 hr Did you know that you can use MBS FileMaker Plugin in the Data API and provide an API to the outside world to produce PDFs?You can have an external request come in to start a script, have the script create a PDF based on the given script parameters and then store it in a contaner field. Then another call can download that specific PDF from the container field. We use a global field here for the temporary storage. On a server script, global fields act like global variables and each session has their own one. So unless you prefer to store the PDF in a new record, you could simply use a global field to keep it until the session is finished.Let's start with installation. The MBS FileMaker Plugin and the dynapdf library files go into the /FileMaker Server/Web Publishing/publishing-engine/wip/Plugins/ folder. After you copied the plugin there, you need to restart the wip process for Data API to have it load it. Once loaded you see a new log file in the Logs folder. When the dynapdf library is in the same folder as the plugin, we can load it with "" as path. If you registered the MBS server license before on the scripting engine, the MBS FileMaker Plugin for Data API should pick that up. But it is always good to have an MBS register script to apply the license if IsRegistered functions returns a zero.Here is a sample script to make a PDF with text from the script parameter:# Initialize DynaPDF if needed If [ MBS("DynaPDF.IsInitialized") ≠ 1 ] Perform Script [ “InitDynaPDF” ; Specified: From list ; Parameter: ] End If # Go to Layout [ “Asset Details” (Assets) ; Animation: None ] # # Start with a new PDF document Set Variable [ $pdf ; Value: MBS("DynaPDF.New") ] # Add page Set Variable [ $r ; Value: MBS("DynaPDF.AppendPage"; $pdf) ] Set Variable [ $r ; Value: MBS("DynaPDF.SetPageCoords"; $pdf; "topdown") ] Set Variable [ $r ; Value: MBS("DynaPDF.SetFont"; $pdf; "Helvetica"; 0; 12) ] # Write some text Set Variable [ $text ; Value: "Parameter: " & Get(ScriptParameter) ] Set Variable [ $r ; Value: MBS("DynaPDF.SetFillColor"; $pdf; 0; 0; 0) ] Set Variable [ $r ; Value: MBS("DynaPDF.WriteStyledTextEx"; $pdf; 10; 10; 300; -1; "justify"; $Text) ] # now figure out how much space we needed to make the page the right size Set Variable [ $height ; Value: MBS("DynaPDF.GetLastTextPosY"; $pdf) ] Set Variable [ $ph ; Value: MBS("DynaPDF.GetPageHeight"; $pdf) ] Set Variable [ $r ; Value: MBS( "DynaPDF.SetBBox"; $PDF; "Media"; 0; $ph; 320; $height - 10 ) ] # close page, document and save PDF Set Variable [ $r ; Value: MBS("DynaPDF.EndPage"; $pdf) ] Set Variable [ $Result ; Value: MBS("DynaPDF.Save"; $pdf; "hello.pdf") ] Set Variable [ $r ; Value: MBS("DynaPDF.Release"; $pdf) ] # Put in Container Set Field [ Assets::PDF ; $Result ] Exit Script [ Text Result: "PDF Created" ]Let's call this script from the outside. This could be in FileMaker again, but we could use the curl command line tool. We have to make the following API calls:We start by asking for a new session token. The query goes to the URL of our server, e.g. "https://10.211.55.16" for the local server here. Then we need to specify which database we use and what credentials we have. Also we need to pass some JSON with further options, but since we have none, this is just "{}".curl -s -k -X POST \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions" \ -H "Content-Type: application/json" \ -u "${USERNAME}:${PASSWORD}" \ -d "{}"From the result, we extract the session token.We continue with triggering the script. This time we need to specify a layout and for this we made a specific PDFLayout, which only has the fields needed for the script. Here we can pass a parameter, which needs to be URL encoded. But you can pass JSON here if you need structured data.curl -s -k \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/script/CreatePDF?script.param=${ENCODED_PARAM}" \ -H "Authorization: Bearer ${TOKEN}The result should indicate the script run through and provide the script result. That allows the script to return the record ID for a new record or a JSON for more detailed structured response. In our case we return the PDF via a global field, so we don't need a record ID.Time to query the first record to get the URL to download the PDF. We query the records and limit the output to one record. Since FileMaker likes to set a session cookie for the download of the PDF, we need to tell CURL to keep cookies.curl -s -k \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/records?_limit=1" \ -H "Authorization: Bearer ${TOKEN}" \ -c "${COOKIE_FILE}The result is a JSON which contains the PDF download URL.Once we have the URL, we do the download:curl -s -k \ -H "Authorization: Bearer ${TOKEN}" \ -b "${COOKIE_FILE}" \ -o "${OUTPUT_FILE}" \ "${PDF_URL}"This writes the PDF directly to the output file.On the end of the script, we need to close the session, which also releases the global field:curl -s -k -X DELETE \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions/${TOKEN}"Here is a shell script doing all the steps in Terminal: #!/usr/bin/env bash set -euo pipefail # ----------------------------------------------------------------------------- # Configuration # ----------------------------------------------------------------------------- BASE_URL="https://10.211.55.16" DATABASE="Assets" LAYOUT="PDFLayout" USERNAME="user" PASSWORD="user" SCRIPT_PARAM="Hello World" COOKIE_FILE="cookies.txt" OUTPUT_FILE="test.pdf" # ----------------------------------------------------------------------------- # Step 1: Create session and get token # ----------------------------------------------------------------------------- echo "Creating session..." SESSION_RESPONSE=$(curl -s -k -X POST \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions" \ -H "Content-Type: application/json" \ -u "${USERNAME}:${PASSWORD}" \ -d "{}") echo "Session response:" echo "${SESSION_RESPONSE}" TOKEN=$(echo "${SESSION_RESPONSE}" | sed -n 's/.*"token":"\([^"]*\)".*/\1/p') if ; then echo "ERROR: Could not extract token" exit 1 fi echo "Token: ${TOKEN}" # ----------------------------------------------------------------------------- # Step 2: Run FileMaker script # ----------------------------------------------------------------------------- ENCODED_PARAM=$(printf '%s' "${SCRIPT_PARAM}" | sed 's/ /%20/g') echo "Running CreatePDF script..." SCRIPT_RESPONSE=$(curl -s -k \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/script/CreatePDF?script.param=${ENCODED_PARAM}" \ -H "Authorization: Bearer ${TOKEN}" \ -c "${COOKIE_FILE}") echo "Script response:" echo "${SCRIPT_RESPONSE}" # ----------------------------------------------------------------------------- # Step 3: Get one record and extract PDF URL # ----------------------------------------------------------------------------- echo "Fetching record..." RECORD_RESPONSE=$(curl -s -k \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/layouts/${LAYOUT}/records?_limit=1" \ -H "Authorization: Bearer ${TOKEN}" \ -c "${COOKIE_FILE}") echo "Record response:" echo "${RECORD_RESPONSE}" PDF_URL=$(echo "${RECORD_RESPONSE}" | sed -n 's/.*"PDF":"\([^"]*\)".*/\1/p') # Unescape JSON escaped slashes PDF_URL=$(echo "${PDF_URL}" | sed 's#\\/#/#g') if ; then echo "ERROR: Could not extract PDF URL" exit 1 fi echo "PDF URL:" echo "${PDF_URL}" # ----------------------------------------------------------------------------- # Step 4: Download PDF # ----------------------------------------------------------------------------- echo "Downloading PDF..." curl -s -k \ -H "Authorization: Bearer ${TOKEN}" \ -b "${COOKIE_FILE}" \ -o "${OUTPUT_FILE}" \ "${PDF_URL}" echo "PDF downloaded to ${OUTPUT_FILE}" # ----------------------------------------------------------------------------- # Step 5: Delete session # ----------------------------------------------------------------------------- echo "Deleting session..." curl -s -k -X DELETE \ "${BASE_URL}/fmi/data/v2/databases/${DATABASE}/sessions/${TOKEN}" echo echo "Session deleted" # ----------------------------------------------------------------------------- # Step 6: Cleanup # ----------------------------------------------------------------------------- rm -f "${COOKIE_FILE}" echo "Cookies removed" echo "Done" When you run such a script, you see the following output:Creating session... Session response: {"response":{"token":"5d203f8e9fa48ae10dda519ac3a79513b44ec1a7cc486d9f8a25"},"messages":[{"code":"0","message":"OK"}]} Token: 5d203f8e9fa48ae10dda519ac3a79513b44ec1a7cc486d9f8a25 Running CreatePDF script... Script response: {"response":{"scriptResult":"PDF Created","scriptError":"0"},"messages":[{"code":"0","message":"OK"}]} Fetching record... Record response: { "response": { "dataInfo": { "database": "Assets", "layout": "PDFLayout", "table": "Assets", "totalRecordCount": 25, "foundCount": 25, "returnedCount": 1 }, "data": [ { "fieldData": { "PDF": "https://10.211.55.16:443/Streaming/MainDB/77C8957F305297674C98AF4F9DCF 5847722CC4D1F525316A33B3412DAC81D9B7.pdf?RCType=EmbeddedRCFileProcessor" }, "portalData": {}, "recordId": "1", "modId": "25" } ] }, "messages": [ { "code": "0", "message": "OK" } ] } PDF URL: https://10.211.55.16:443/Streaming/MainDB/77C8957F305297674C98AF4F9DCF 5847722CC4D1F525316A33B3412DAC81D9B7.pdf?RCType=EmbeddedRCFileProcessor Downloading PDF... PDF downloaded to test.pdf Deleting session... {"response":{},"messages":[{"code":"0","message":"OK"}]} Session deleted Cookies removed Done Please try this. Generating PDF documents on the fly using Data API calls may be very useful. Especially if you use data in the database to fill the records. FileMaker may create a temporary PDF from some records and then you post process them with DynaPDF. e.g. adding page numbers, watermarks or signatures. And this could be called from a custom facing website to download receipts or confirmations on demand.On the security note, please keep such an API to a separate file with specific logins and only the scripts, records and fields people should see from the outside. Don't let anyone access the whole solution and cause damage.See alsoDynaPDF InterviewQ&A DynaPDF & SearchDynaPDF in FileMaker
Create an account or sign in to comment