Build a Simple Media Connector
This guide walks you through the process of creating a simple media connector using the Connector CLI tool. The connector will display images from picsum.photos in the image selector of GraFx Studio Designer Workspace.
Requirements
- Node.js or Bun.js
- Connector CLI tool
- Environment Admin user with a Template Designer license applied
Creating a New Connector Project
- Run the command command to create a new connector project:
- Change to the newly created directory:
- Install dependencies:
- Open
connector.ts
as this is the main connector file we will be modifying.
Modifying the Query Method
Our goal is to display images from picsum.photos in the image selector. The query
method is utilized by the default Studio GUIs to retrieve a list of Media
objects for display.
Updating Capabilities
First, we need to modify the getCapabilities()
method to inform the UI about our connector's supported capabilities:
getCapabilities(): Media.MediaConnectorCapabilities {
return {
query: true,
detail: true,
filtering: true,
metadata: false,
};
}
Note: We set both query
and filtering
to true
. Ideally, we only want to support query
, but currently, it's not possible to have query
without filtering
for the default Studio GUIs. This limitation may be addressed in future updates.
Implementing the Query Method
Next, we'll modify the query
method to perform the following tasks:
- Fetch a list of photos from picsum.photos
- Transform the data to match the required
Media
type - Return the
Media
data within the expectedMediaPage
type
We'll use the following endpoint to retrieve our photos:
This endpoint returns 30 images per page in an array of objects with the following structure:
{
"id": string;
"author": string;
"width": number;
"height": number;
"url": string;
"download_url": string;
}
Now, let's update our query
method to handle this data and return the expected MediaPage
type:
async query(
options: Connector.QueryOptions,
context: Connector.Dictionary
): Promise<Media.MediaPage> {
const resp = await this.runtime.fetch("https://picsum.photos/v2/list?page=1", {
method: "GET"
});
if (resp.ok) {
const data = JSON.parse(resp.text);
// Transform the data to match the Media type
const dataFormatted = data.map(d => ({
id: d.id,
name: d.id,
relativePath: "/",
type: 0,
metaData: {}
})) as Array<any>;
return {
pageSize: options.pageSize, // Note: pageSize is not currently used by the UI
data: dataFormatted,
links: {
nextPage: "" // Pagination is ignored in this example
}
}
}
// Handle error case
throw new Error("Failed to fetch images from picsum.photos");
}
Notes on Query Options
- The
options
parameter provides query options set by the UI. Currently, only thepageToken
property is utilized and it is only for pagination. - The returned
nextPage
in theMediaPage.links
is meant to be passed back aspageToken
during pagination, but it only works in a very specific use-case. - The
pageSize
property withinoptions
is intended to specify the number of elements the UI can display. However, it is currently hardcoded and not functional. - The returned
pageSize
in theMediaPage
object also has no effect at present.
Publishing the Connector
Step 1: Logging In
Before publishing your connector, you need to log in to your environment. Run the following command and follow the on-screen instructions:
Step 2: Publishing
After successfully logging in, you can publish your connector using the following command:
connector-cli publish -e <environment-name> \
-b <base-url> \
-n <name> \
--proxyOption.allowedDomains "*.xyz"
Command Arguments
-e <environment-name>
: The name of the environment you logged into in the previous step.-b <base-url>
: The base URL for GraFx API calls. Use one of the following formats:- Production Environments:
https://{environment}.chili-publish.online/grafx
- Sandbox Environments:
https://{environment}.chili-publish-sandbox.online/grafx
-n <name>
: The name of your connector as it will appear in the Studio UI.--proxyOption.allowedDomains "*.xyz"
: Specifies allowed domains for OAuth, but is required even though not used.
Grab the Connector ID
Make sure to copy and save the resulting Connector ID after publishing. Currently, there is no way to retrieve this ID later without using the Environment API.
Step 3: Verifying the Publication
To verify that your connector has been published successfully:
- Open GraFx Studio Designer Workspace.
- Create or open an existing template.
- Navigate to the media panel.
At this point, you should see missing image placeholders for images numbered 0 through 29. This is expected behavior, as we haven't implemented the download
method yet.
Implementing the Download Method
The images don't load initially because we haven't implemented the download
method. This method is called by the engine or UI whenever an image needs to be displayed.
Understanding the Download Method
The download
method handles two main scenarios:
- Fetching thumbnails for the image selector UI
- Fetching full-size images for other use cases (editor and output)
Implementing the Download Method
Here's the implementation of the download
method:
async download(
id: string,
previewType: Media.DownloadType,
intent: Media.DownloadIntent,
context: Connector.Dictionary
): Promise<Connector.ArrayBufferPointer> {
switch (previewType) {
case "thumbnail": {
const picture = await this.runtime.fetch(`https://picsum.photos/id/${id}/200`, { method: "GET" });
return picture.arrayBuffer;
}
default: {
const picture = await this.runtime.fetch(`https://picsum.photos/id/${id}/1000`, { method: "GET" });
return picture.arrayBuffer;
}
}
}
This method:
- Checks the
previewType
to determine whether a thumbnail or full-size image is required - Fetches the appropriate image from picsum.photos
- Returns the image data as an
ArrayBufferPointer
Publishing and Testing the Updated Connector
After implementing the download
method, you need to republish your connector with the updates.
Republishing the Connector
Use the following command to republish your connector, including the --connectorId
argument:
connector-cli publish -e <environment-name> \
-b <base-url> \
-n <name> \
--proxyOption.allowedDomains "*.xyz" \
--connectorId <connector-id>
Replace <connector-id>
with the ID you received when first publishing the connector.
If you've forgotten your connector ID, you can retrieve it using the following API endpoint:
GET https://{environment}.chili-publish.online/grafx/api/experimental/environment/{environment}/connectors
Replace {environment}
with your environment name.
Testing the Connector
To test your updated connector:
- Open GraFx Studio Designer Workspace
- Navigate to the Media panel
- Verify that images now appear properly in the Media panel
- Then add an image frame to your design
- Double-click an image in the Media panel to fill the frame
Some Issues
Issue: Only First Image
You may notice that no matter which image you select in the Media panel, the image displayed in the template is instead the first image. This is due to how download
behaves when filtering
is true
.
When filtering
is false
, download
is called directly with the selected asset ID. However, when it is set to true
, query
is called first and then the first item from the call will be pushed into download
.
Issue: Double-clicking with Nothing Selected
You may notice that double-clicking an image in the Media panel when nothing is selected doesn't have any effect. This is due to a missing capability in our connector.
If you open the developer console, you'll see an error message:
This error occurs because we haven't implemented the detail
method in our connector, which is required for this specific functionality.
Fixing query
When query
is called before download
, the options.pageSize
will be the value 1
and options.collection
will be null
.
async query(
options: Connector.QueryOptions,
context: Connector.Dictionary
): Promise<Media.MediaPage> {
// When pageSize is 1 & collection is null, we know that query is called before download
if (options.pageSize == 1 && !options.collection) {
return {
pageSize: options.pageSize, // Note: pageSize is not currently used by the UI
data: [{
id: options.filter[0],
name: "",
relativePath: "",
type: 0,
metaData: {}
}],
links: {
nextPage: "" // Pagination is ignored in this example
}
}
}
// If pageSize is bigger than 1, we do a normal query
const resp = await this.runtime.fetch("https://picsum.photos/v2/list?page=1&limit=4", {
method: "GET"
});
if (resp.ok) {
const data = JSON.parse(resp.text);
// Transform the data to match the Media type
const dataFormatted = data.map(d => ({
id: d.id,
name: d.id,
relativePath: "/",
type: 0,
metaData: {}
})) as Array<any>;
return {
pageSize: options.pageSize, // Note: pageSize is not currently used by the UI
data: dataFormatted,
links: {
nextPage: "" // Pagination is ignored in this example
}
}
}
// Handle error case
throw new Error("Failed to fetch images from picsum.photos");
}
Implementing the Detail Method
The detail
method is used to define the initial width and height of the image frame when selected from the Media panel. Although this method accepts several parameters, only the width and height are relevant for this purpose. However, it's important to note that the type signature tells you the width and height is not mandatory, but the behavior of the method requires them present.
Basic Implementation
Here's a basic implementation of the detail
method:
async detail(
id: string,
context: Connector.Dictionary
): Promise<Media.MediaDetail> {
return {
name: id,
id: id,
metaData: {},
relativePath: "/",
type: 0
}
}
With this implementation, when you double-click an image in the Media panel, it will be added to the design in a 100x100 pixel frame (the default size when width and height are not specified).
Customizing Frame Size
To customize the initial frame size, you can include width
and height
properties in the returned object. For example, to set a 200x200 pixel frame:
async detail(
id: string,
context: Connector.Dictionary
): Promise<Media.MediaDetail> {
return {
name: id,
id: id,
metaData: {},
relativePath: "/",
type: 0,
width: 200,
height: 200
}
}
Publishing and Testing
After implementing the detail
method:
- Republish your connector using the
connector-cli publish
command (as described in previous sections). - Open GraFx Studio Designer Workspace.
- Test the functionality by double-clicking an image in the Media panel.
- Verify that the image is added to the design with the correct initial frame size.
Conclusion
Congratulations! You've successfully built your first Media Connector for GraFx Studio. This connector allows you to integrate images from picsum.photos into the GraFx Studio Designer Workspace.
Key Accomplishments
In this tutorial, you've learned how to:
- Set up a new connector project
- Implement the
query
method to fetch and display images - Create a
download
method to retrieve image data - Add a
detail
method to control initial frame sizes - Publish and test your connector in the GraFx Studio environment
Next Steps
- Review the Comprehensive Connector Documentation for in-depth information on connector functionality and best practices.
- Follow the Add Variable Settings To Your Connector tutorial to learn how to add variable settings in your Connectors.