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.
2. 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.
3. 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.
4. 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.
5. 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"


