Werk24 API - Drawing Processing with Callback / Webhook¶
This tutorial demonstrates using the Werk24 API asynchronously to process a drawing and receive information via a callback URL. We'll focus on retrieving the title block information, but you can adapt this code for other data types.
Prerequisites¶
- A Werk24 account and API key.
- Python 3 with the
werk24
library installed (pip install werk24
). - A Technical Drawing. You can download an example from here: DRAWING_SUCCESS.png
Understanding Asynchronous Programming:¶
This example uses asynchronous programming, which allows your program to perform multiple tasks concurrently without blocking the main thread. This can be beneficial for long-running operations like processing drawings.
Steps¶
Import necessary libraries¶
from asyncio import run
from werk24.utils import W24TechreadClient
from werk24.models.ask import W24AskTitleBlock
Define the read_file function¶
This asynchronous function reads the contents of your drawing file, defines the information to retrieve, and initiates the Werk24 API call with a callback URL.
file_path
: Path to your drawing file.callback_url
: URL where Werk24 will send the processed information (replace with your actual callback URL).authorization_header
: Authorization header containing your OWN authorization key. This allows you to authenticate against your own endpoint.
async def read_file(
file_path: str,
callback_url: str = 'https://example.com/callback',
authorization_token: str = 'Bearer long-lived-token'
x_auth_token: str = "Bearer short-lived-token"
):
with open(file_path, 'rb') as fid:
document_bytes = fid.read()
asks = [W24AskTitleBlock()] # Request title block information
callback_url = 'https://example.com/callback' # Replace with your callback URL
async with W24TechreadClient.make_from_env() as session:
request_id = await session.read_drawing_with_callback(
document_bytes,
asks=asks,
callback_url=callback_url,
callback_headers={
"Authorization": authorization_header,
"X-Auth-Token": x_auth_token,
}
)
print(f"Sent request with id '{request_id}'")
Run the asynchronous function:¶
The run function from the asyncio library executes the asynchronous read_file function.
if __name__ == "__main__":
run(read_file('DRAWING_SUCCESS.png'))
Explanation¶
- The read_file function first reads the drawing data from the file.
- It then defines a list of asks specifying the desired information (title block in this case). The function creates a W24TechreadClient object using your environment variables (assuming your API key is set).
- The read_drawing_with_callback method sends the drawing data, requested information (asks), and callback URL to the Werk24 API.
- An additional header is included in the callback (Authorization) containing your API key for authentication.
Expected Callbacks¶
You will receive multiple callbacks. Your endpoint must be able to handle all of them.
First Callback Process Started¶
The first first callback informs you that the file has been picked up from the queue and the processing of the file has been started. The content will be a W24TechreadMessage
of the followign structure
from werk24.models.techread import W24TechreadMessage, W24TechreadMessageType, W24TechreadMessageSubtypeProgress
started_message = W24TechreadMessage(
request_id=<request_id>,
message_type=W24TechreadMessageType.PROGRESS,
message_subtype=W24TechreadMessageSubtypeProgress.STARTED,
page_number=-1
payload_dict=None,
payload_url=None,
payload_bytes=None
)
Second+ Callbacks: Data¶
You will now receive multiple data callbacks. The number of callbacks depends on the asks that you specified in the request and the exact file that you are processing. The first term of the Ask gives you an indication of how many responses you will receive. For example W24AskPageThumbnail will trigger 1 callback for every Page in the document; the W24AskSectionalThumbnail, we trigger 1 callback for each Sectional in the Document.
The content of the callback will follow the same basic pattern as before. As an example below the response for a PageThumbnail Ask
from werk24.models.techread import W24TechreadMessage, W24TechreadMessageType, W24TechreadMessageSubtypeProgress
data_message = W24TechreadMessage(
request_id=<request_id>,
message_type=W24TechreadMessageType.ASK,
message_subtype=W24AskType.PAGE_THUMBNAIL,
page_number=-1
payload_dict=None,
payload_url="https://presigned-url",
payload_bytes=None
)
payload_bytes
will never be set in a callback. You will need to implement your own download functionality. Please be aware of the short-lived nature of the payload_url
. The url expires after 5 minutes. When using the webhook functionality, you will need to handle the response deserialization yourself. A simple example looks like this
import logging
from werk24.models.title_block import W24TitleBlock
if data_message.message_type == W24TechreadMessageType.ASK:
model = {
W24AskType.TITLE_BLOCK: W24TitleBlock
}.get(data_message.message_subtype, None)
if model is None:
logging.error(f"Unknown model for AskType {data_message.message_subtype}")
exit(1)
payload = model.model_validate(message.payload_dict)
To perform the error handling, you can now check for exceptions
if payload.exceptions:
# exceptions is a list of `W24TechreadException`
exception_string = "; ".join(e.exception_type for e in payload.exceptions)
warning = "Processing ask {data_message.message_subtype} of the request '{request_id}' was unsucessful. Exceptions: '{exception_string}'"
logging.warning(warning)
Last Callback: Process Completed¶
Because the number of callbacks is not known in advance, you need to wait for the Process Completed message
from werk24.models.techread import W24TechreadMessage, W24TechreadMessageType, W24TechreadMessageSubtypeProgress
completed_message = W24TechreadMessage(
request_id=<request_id>,
message_type=W24TechreadMessageType.PROGRESS,
message_subtype=W24TechreadMessageSubtypeProgress.COMPLETED,
page_number=-1
payload_dict=None,
payload_url=None,
payload_bytes=None
)
!!! note We also encourage you to implement a timeout. It can always occure that a server goes offline (out of memory exceptions, network outage, etc.). The workers are running into an internal timeout 120 seconds after the started processing the file. You can thus set a timeout of 150 seconds and perform an internal error handling if if the timeout is reached.
Important Notes:¶
- Remember to replace "DRAWING_SUCCESS.png" with the actual path to your drawing file.
- Make sure you have a functional callback URL set up to receive the processed information from Werk24 and that the url is available from the public internet.
- This tutorial demonstrates a basic asynchronous approach. You'll need to implement logic on your callback URL to handle the received data.
Important Security Considersations¶
- Authorization Token: Update the authorization token you provide in the callback header. This token is not related to Werk24 itself. It's a custom mechanism you can use to restrict access to your callback URL.
-
Protection Layers: Werk24 provides a unique request_id for each request, offering some protection. However, it's highly recommended to add another layer of security using a combination of:
-
Short-lived authorization tokens: These tokens expire quickly, limiting the window for potential misuse.
-
Long-lived authorization tokens: These can be used at the API gateway level to protect against Denial-of-Service (DoS) attacks. By requiring a valid token at the gateway, you prevent malicious actors from overwhelming your callback URL with requests.
-
-
The exact naming and logic of the tokens is depends on your own setup. Please implement this callback functionality in close collaboration with your Cyber Information Security Officer.