Lightyear Docs
Connectors

Model connectors

What is a model connector?

A model connector is a TypeScript class that synchronizes data between an app and a specific model within a collection. Its purpose is to handle the reading and writing of data for a particular data model (such as Contacts, Tickets, or Invoices) within a sync integration.

  • Schema Mapping: Model connectors are responsible for mapping data to and from your product's model schema and the external app's schema.
  • Usage:
    • You need one model connector for each model you want to sync in a data collection.
    • Typically, a sync connector includes several model connectors—one for each data type being managed.

Example: If your integration syncs both "Accounts" and "Contacts" from Salesforce, you'll have a model connector for "Accounts" and another for "Contacts," each managing the translation and data flow for its respective model.

Using a built-in model connector

  • Bundled with Sync Connectors: Built-in model connectors come predefined as part of our built-in sync connectors for popular apps.

  • Extendability: If a built-in model connector doesn't quite meet your requirements (for example, if you need to map a custom field), you can extend the built-in model connector to add or override specific mapping or data handling functionality.

Defining a model connector

import {
  ModelConnector,
  ModelConnectorProps,
  ListProps,
  CreateBatchProps,
  UpdateBatchProps,
  DeleteBatchProps,
} from "@runlightyear/lightyear";
import { TodoApp } from "./TodoApp";
 
export interface TaskModelProps extends ModelConnectorProps {
  todoApp: TodoApp;
}
 
export class TaskModel extends ModelConnector<any, any, any, any> {
  todoApp: TodoApp;
 
  constructor(props: TaskModelProps) {
    super(props);
    this.todoApp = props.todoApp;
  }
 
  getNoun(): string {
    return "task";
  }
 
  validateListResponse(response: any): any {
    return response.data;
  }
 
  mapExternalToObject(data: any): any {
    return {
      id: data.id,
      updatedAt: data.updated_at,
      createdAt: data.created_at,
      title: data.title,
      description: data.description,
      status: data.status,
      dueDate: data.due_date,
      completedAt: data.completed_at,
    };
  }
 
  mapObjectDataToExternalData(data: any): any {
    return {
      title: data.title,
      description: data.description,
      status: data.status,
      due_date: data.dueDate,
      completed_at: data.completedAt,
    };
  }
 
  async list(props: ListProps): Promise<any> {
    const response = await this.todoApp.request({
      method: "GET",
      url: "/tasks",
      params: {
        limit: 100,
        orderBy: "updated_at",
        after: props.cursor ?? undefined,
      },
    });
 
    const validatedResponse = this.validateListResponse(response.data);
 
    return {
      objects: validatedResponse.results.map((result: any) =>
        this.mapExternalToObject(result),
      ),
      cursor: validatedResponse.cursor,
    };
  }
 
  async createBatch(props: CreateBatchProps<any>): Promise<any> {
    await this.todoApp.requestBatch(
      props.changes.map((change: any) => ({
        method: "POST",
        url: "/tasks",
        data: this.mapObjectDataToExternalData(change.object),
      })),
    );
  }
 
  async updateBatch(props: UpdateBatchProps<any>): Promise<any> {
    await this.todoApp.requestBatch(
      props.changes.map((change: any) => ({
        method: "PUT",
        url: `/tasks/${change.externalId}`,
        data: this.mapObjectDataToExternalData(change.object),
      })),
    );
  }
 
  async deleteBatch(props: DeleteBatchProps): Promise<any> {
    await this.todoApp.requestBatch(
      props.changes.map((change: any) => ({
        method: "DELETE",
        url: `/tasks/${change.externalId}`,
      })),
    );
  }
}

On this page