Ir para o conteúdo principal

Criando plugins personalizados

Criando plugins personalizados

Se você precisar de rotas de API personalizadas ou de lógica em segundo plano, implemente um plugin do AppKit. A maneira mais rápida é usar a CLI:

# Interativo
npx @databricks/appkit plugin create

# Não interativo
npx @databricks/appkit plugin create --placement in-repo --path plugins/my-plugin --name my-plugin --description "My plugin" --force

Para entender melhor a estrutura do plugin, continue lendo.

Exemplo básico de plugin

Escreva o manifesto em JSON, importe-o e associe-o a uma subclasse de Plugin por meio de static manifest. Exporte com toPlugin():

// my-plugin/manifest.json
{
  "$schema": "https://databricks.github.io/appkit/schemas/plugin-manifest.schema.json",
  "name": "my-plugin",
  "displayName": "My Plugin",
  "description": "A custom plugin",
  "resources": {
    "required": [
      {
        "type": "secret",
        "alias": "apiKey",
        "resourceKey": "api-key",
        "description": "API key for external service",
        "permission": "READ",
        "fields": {
          "scope": { "env": "MY_SECRET_SCOPE", "description": "Secret scope" },
          "key": { "env": "MY_API_KEY", "description": "Secret key name" }
        }
      }
    ],
    "optional": []
  }
}
// my-plugin/index.ts
import { Plugin, toPlugin, type PluginManifest } from "@databricks/appkit";
import manifest from "./manifest.json";

class MyPlugin extends Plugin {
  static manifest = manifest as PluginManifest<"my-plugin">;

  async setup() {
    // Inicialize seu plugin
  }

  myCustomMethod() {
    // Alguma implementação
  }

  async shutdown() {
    // Libere os recursos
  }

  exports() {
    return {
      myCustomMethod: this.myCustomMethod
    }
  }
}

export const myPlugin = toPlugin(MyPlugin);

O JSON é a superfície canônica de autoria — é o que o appkit plugin sync lê ao agregar manifestos para os modelos. Para o contrato completo do manifesto v2.0 (recursos, descritores de descoberta, regras de scaffolding), consulte Manifesto do plugin.

Recursos dependentes de configuração

O manifesto define os recursos como required (sempre necessários) ou optional (podem ser necessários). Para recursos que se tornam obrigatórios conforme a configuração do plugin, implemente um método estático getResourceRequirements(config):

interface MyPluginConfig extends BasePluginConfig {
  enableCaching?: boolean;
}

class MyPlugin extends Plugin<MyPluginConfig> {
  static manifest = {
    name: "myPlugin",
    displayName: "My Plugin",
    description: "A plugin with optional caching",
    resources: {
      required: [
        { type: "sql_warehouse", alias: "warehouse", resourceKey: "sqlWarehouse", description: "Query execution", permission: "CAN_USE", fields: { id: { env: "DATABRICKS_WAREHOUSE_ID" } } }
      ],
      optional: [
        // Listado como opcional no manifesto para análise estática
        { type: "database", alias: "cache", resourceKey: "cache", description: "Query result caching (if enabled)", permission: "CAN_CONNECT_AND_CREATE", fields: { instance_name: { env: "DATABRICKS_CACHE_INSTANCE" }, database_name: { env: "DATABRICKS_CACHE_DB" } } }
      ]
    }
  } satisfies PluginManifest<"myPlugin">;

  // Runtime: converte recursos opcionais em obrigatórios conforme a configuração
  static getResourceRequirements(config: MyPluginConfig) {
    const resources = [];
    if (config.enableCaching) {
      // Quando o cache está ativado, o Database passa a ser obrigatório
      resources.push({
        type: "database",
        alias: "cache",
        resourceKey: "cache",
        description: "Query result caching",
        permission: "CAN_CONNECT_AND_CREATE",
        fields: {
          instance_name: { env: "DATABRICKS_CACHE_INSTANCE" },
          database_name: { env: "DATABRICKS_CACHE_DB" },
        },
        required: true  // Marca como obrigatório em runtime
      });
    }
    return resources;
  }
}

Esse padrão permite:

  • Que ferramentas estáticas (CLI, documentação) exibam todos os recursos possíveis
  • Que a validação em runtime aplique os recursos com base na configuração real

Principais pontos de extensão

  • Injeção de rotas: implemente injectRoutes() para adicionar endpoints personalizados usando IAppRouter
  • Hooks de ciclo de vida: sobrescreva os métodos setup() e shutdown()
  • Serviços compartilhados:
    • Gerenciamento de cache: acesse o serviço de cache por meio de this.cache. Consulte CacheConfig para a configuração.
    • Telemetria: instrumente seu plugin com traces e métricas por meio de this.telemetry. Consulte ITelemetry.
  • Interceptadores de execução: use execute() e executeStream() com StreamExecutionSettings para obter cache, retry e timeout automáticos, além dos atributos de span de telemetria (execution.context, caller.id)

Consumindo seu plugin programaticamente

Se desejar, você pode oferecer uma forma de consumir seu plugin programaticamente usando o objeto AppKit. Para isso, seu plugin precisa implementar o método exports, retornando um objeto com os métodos que deseja expor. Com base no exemplo anterior, o plugin poderia ser consumido assim:

const AppKit = await createApp({
  plugins: [
    server({ port: 8000 }),
    analytics(),
    myPlugin(),
  ],
});

AppKit.myPlugin.myCustomMethod();

Consulte a referência da API Plugin para a documentação completa.

Databricks Developer Hub

Pronto para lançar seu próximo aplicativo baseado em agentes em minutos?

Ler a documentação