Accéder au contenu principal

Créer des plugins personnalisés

Créer des plugins personnalisés

Si vous avez besoin de routes d'API personnalisées ou de logique en arrière-plan, implémentez un plugin AppKit. Le plus rapide est de passer par la CLI :

# Interactif
npx @databricks/appkit plugin create

# Non interactif
npx @databricks/appkit plugin create --placement in-repo --path plugins/my-plugin --name my-plugin --description "My plugin" --force

Pour mieux comprendre la structure d'un plugin, poursuivez votre lecture.

Exemple de plugin simple

Rédigez le manifeste en JSON, importez-le, puis associez-le à une sous-classe de Plugin via static manifest. Exportez-le avec 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() {
    // Initialisez votre plugin
  }

  myCustomMethod() {
    // Implémentation à compléter
  }

  async shutdown() {
    // Libérez les ressources
  }

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

export const myPlugin = toPlugin(MyPlugin);

JSON est le format d'écriture de référence : c'est ce que lit appkit plugin sync lorsqu'il agrège les manifestes des modèles. Pour le contrat complet du manifeste v2.0 (ressources, descripteurs de découverte, règles de génération d'ossature), voir Manifeste de plugin.

Ressources dépendantes de la configuration

Le manifeste déclare les ressources comme required (toujours nécessaires) ou optional (potentiellement nécessaires). Pour les ressources qui deviennent obligatoires selon la configuration du plugin, implémentez une méthode statique 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: [
        // Déclarée comme facultative dans le manifeste pour l'analyse statique
        { 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 : convertit les ressources facultatives en ressources requises selon la configuration
  static getResourceRequirements(config: MyPluginConfig) {
    const resources = [];
    if (config.enableCaching) {
      // Lorsque la mise en cache est activée, Database devient requise
      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  // Marquée comme requise au runtime
      });
    }
    return resources;
  }
}

Ce modèle permet :

  • aux outils statiques (CLI, documentation) d'afficher toutes les ressources possibles ;
  • à la validation au runtime d'imposer les ressources en fonction de la configuration réelle.

Points d'extension clés

  • Injection de routes : implémentez injectRoutes() pour ajouter des endpoints personnalisés à l'aide de IAppRouter
  • Hooks de cycle de vie : surchargez les méthodes setup() et shutdown()
  • Services partagés :
    • Gestion du cache : accédez au service de cache via this.cache. Voir CacheConfig pour la configuration.
    • Télémétrie : instrumentez votre plugin avec des traces et des métriques via this.telemetry. Voir ITelemetry.
  • Intercepteurs d'exécution : utilisez execute() et executeStream() avec StreamExecutionSettings pour bénéficier automatiquement de la mise en cache, des nouvelles tentatives, du délai d'expiration et des attributs de span de télémétrie (execution.context, caller.id)

Utiliser votre plugin par programmation

Vous pouvez, si vous le souhaitez, permettre l'utilisation de votre plugin par programmation via l'objet AppKit. Pour cela, votre plugin doit implémenter la méthode exports, qui renvoie un objet contenant les méthodes que vous souhaitez exposer. En reprenant l'exemple précédent, le plugin s'utiliserait comme suit :

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

AppKit.myPlugin.myCustomMethod();

Consultez la référence de l'API Plugin pour la documentation complète.

Databricks Developer Hub

Prêt à lancer votre prochaine application agentique en quelques minutes ?

Lire la documentation