Example Project: Custom Content Previewer or Data Lookup Tool
Outline
This module is your opportunity to apply all the concepts learned in this section to build a more complex, real-world Opal tool. You will choose one of two options for your capstone project for this module. Both options require integrating with external data sources and demonstrate practical applications of Opal tools.
By the end of this module, you will be able to:
Design and implement a real-world Opal tool that integrates with an external data source or API.
Apply robust error handling and validation to ensure reliable tool execution.
Demonstrate your end-to-end understanding of the SDK by completing a project.
Project Goal: To build a functional Opal tool using the JavaScript/TypeScript SDK that interacts with an external API or data source, handles parameters, and returns structured data.
Choose ONE of the following options:
Option A: Custom Content Previewer
Scenario: Imagine you have content stored in an external CMS or a custom content repository, and you want to quickly preview its rendered output directly within Optimizely Opal, without having to navigate to another system. This tool will fetch content data and generate a simplified HTML preview.
Tool Name: preview_external_content
Description: Fetches content from an external source and generates a simplified HTML preview.
Parameters:
-
contentId
(Type:String
, Required:true
, Description: "The unique ID of the content item to preview from the external CMS.") -
contentType
(Type:String
, Required:false
, Description: "Optional: The type of content (e.g., 'article', 'product'). May affect how content is rendered.")
Expected Output: A JSON object containing:
-
previewHtml
(string): The generated HTML string for the preview. -
contentTitle
(string): The title of the content. -
externalUrl
(string, optional): A direct link to the content in the external system. -
status
(string): "success" or "error". -
message
(string, optional): Any relevant messages or error details.
Implementation Steps:
- Define the Tool: Create a new TypeScript file (e.g.,
src/tools/ContentPreviewTool.ts
) and define the tool using the@tool()
decorator with the specified name, description, and parameters. - Simulate External CMS API: For this project, you can simulate an external CMS API. You don't need a real CMS. You can create a simple Express route in your
index.ts
or a mock data file that returns different JSON content based on thecontentId
.
Example Mock API Response (for contentId: "article-123"
):
{
"id": "article-123",
"title": "The Future of AI in Marketing",
"author": "Jane Doe",
"body": "<p>Artificial intelligence is rapidly transforming the marketing landscape...</p><p>Key areas include personalization, automation, and data analysis.</p>",
"imageUrl": "https://example.com/ai-marketing.jpg",
"publishDate": "2025-01-15",
"externalLink": "https://external-cms.com/articles/ai-marketing"
}
- Make API Call: Inside your tool's
execute
method, useaxios
orfetch
to call your simulated external CMS API based on thecontentId
parameter. Generate HTML Preview: Parse the JSON response from your simulated CMS. Construct a simple HTML string that represents a "preview" of the content. This might involve:
- Displaying the title as an
<h1>
. - Including the author and publish date.
- Embedding the
body
content (ensure it's sanitized if it contains user-generated HTML to prevent XSS). - Adding an image if
imageUrl
is present. - Adding a link to the
externalUrl
.
- Displaying the title as an
Implement Error Handling:
- If the
contentId
is not found in your mock data, return an error message like "Content not found for ID: [ID]". - Handle any network errors during the API call.
- Ensure your tool returns a clear error message to Opal if something goes wrong.
- If the
Test Thoroughly: Use Postman/Insomnia to test your tool with valid and invalid
contentId
values.
Option B: Data Lookup Tool
Scenario: Your organization has a large product catalog or customer database stored in an external system (e.g., a custom database, a third-party CRM, or a PIM system). You want an Opal tool that can quickly retrieve specific information about a product or customer based on a query, without needing to access the external system directly.
Tool Name: lookup_product_info
(or lookup_customer_details
)
Description: Retrieves detailed information about a product (or customer) from an external database based on its ID or name.
Parameters:
-
productId
(Type:String
, Required:false
, Description: "The unique ID of the product to look up.") -
productName
(Type:String
, Required:false
, Description: "The name of the product to look up (case-insensitive, partial match allowed).") - (Note: Require at least one of
productId
orproductName
)
Expected Output: A JSON object containing:
-
productDetails
(object): An object with details likeid
,name
,price
,stock
,category
,description
. -
status
(string): "success" or "error". -
message
(string, optional): Any relevant messages or error details.
Implementation Steps:
- Define the Tool: Create a new TypeScript file (e.g.,
src/tools/ProductLookupTool.ts
) and define the tool using the@tool()
decorator with the specified name, description, and parameters. - Create Mock Data: Instead of a real database, create a simple array of JavaScript objects in your tool file (or a separate mock data file) to represent your product catalog.
Example Mock Product Data:
const mockProducts = [
{ id: 'PROD001', name: 'Wireless Headphones', price: 129.99, stock: 50, category: 'Audio', description: 'High-quality sound with noise cancellation.' },
{ id: 'PROD002', name: 'Smartwatch X', price: 249.00, stock: 15, category: 'Wearables', description: 'Track your fitness and receive notifications.' },
{ id: 'PROD003', name: 'Portable Charger 10000mAh', price: 35.50, stock: 200, category: 'Accessories', description: 'Fast charging on the go.' },
// ... more products
];
- Implement Lookup Logic: Inside your tool's
execute
method:- First, validate that at least one of
productId
orproductName
is provided. If not, throw an error. - Implement logic to search your
mockProducts
array.- If
productId
is provided, perform an exact match lookup. - If
productName
is provided, perform a case-insensitive partial match. - If both are provided, prioritize
productId
or combine search logic.
- If
- Return the matching product details.
- First, validate that at least one of
- Implement Error Handling:
- If no product is found for the given criteria, return an error message like "Product not found for the provided details."
- Handle cases where neither
productId
norproductName
is provided.
- Test Thoroughly: Use Postman/Insomnia to test your tool with various inputs: valid IDs, valid names, partial names, non-existent IDs/names, and missing parameters.
Project Steps (for either option):
- Planning: Review your chosen option. Clearly define the tool's exact functionality, inputs, and expected outputs. Think about edge cases.
- Tool Definition: Implement the tool using the
@optimizely-opal/opal-tools-sdk
in a new.ts
file within yoursrc/tools
directory. Define itsname
,description
, andparameters
accurately. - Core Logic: Write the JavaScript/TypeScript code to interact with your simulated external data source (mock data or a simple Express route).
- Error Handling: Implement robust
try...catch
blocks and custom validation to handle all anticipated errors gracefully, returning meaningful messages to Opal. - Testing: Thoroughly test your tool using an API client (Postman/Insomnia) by sending requests to your local development server's tool endpoint (e.g.,
<a href="http://localhost:3000/tools/your_tool_name)">http://localhost:3000/tools/your_tool_name)</a>
. Verify both success and error scenarios. - Integration: Ensure your new tool is correctly imported and registered in your main application file (
src/index.ts
orsrc/main.ts
).
Completing this project will significantly enhance your understanding of building practical Opal tools with the JavaScript/TypeScript SDK and prepare you for more complex integrations. Good luck!