Accéder au contenu principal

Génération de types

Génération de types

AppKit peut générer automatiquement les types TypeScript de vos requêtes SQL, garantissant ainsi un typage sûr de bout en bout, de la base de données à l'interface utilisateur.

Objectif

Générer des déclarations TypeScript typées pour les clés de requête, les paramètres et les lignes de résultat.

Tous les fichiers générés se trouvent dans shared/appkit-types/, un par domaine : analytics.d.ts (types des requêtes SQL), serving.d.ts (types des serving endpoints de modèles) et metric-views.d.ts (types des vues de métriques). Une seule commande (et le plugin Vite) les génère tous en une seule passe ; voir Types des vues de métriques. Ces fichiers s'appuient sur declare module pour enrichir les interfaces existantes : les types s'appliquent donc globalement — vous n'avez jamais besoin de les importer. TypeScript les détecte automatiquement grâce à "include": ["shared/appkit-types"] dans votre tsconfig.

Plugin Vite : appKitTypesPlugin

L'approche recommandée consiste à utiliser le plugin Vite, qui surveille vos fichiers SQL et régénère automatiquement les types pendant le développement.

Configuration

  • outFile?: string - Chemin du fichier de sortie (par défaut : shared/appkit-types/analytics.d.ts)
  • watchFolders?: string[] - Dossiers dans lesquels surveiller les fichiers SQL (par défaut : ["../config/queries"])

Exemple

// client/vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { appKitTypesPlugin } from "@databricks/appkit";

export default defineConfig({
  plugins: [
    react(),
    appKitTypesPlugin({
      watchFolders: ["../config/queries"],
    }),
  ],
});

Nuance importante

Lorsque le frontend est servi via AppKit en mode dev, le serveur de développement d'AppKit inclut déjà appKitTypesPlugin() en interne. Il reste toutefois nécessaire dans votre pipeline de build client si vous exécutez vite build séparément.

CLI : npx @databricks/appkit generate-types

Pour générer les types manuellement ou dans des pipelines CI/CD, utilisez la commande CLI :

# Nécessite DATABRICKS_WAREHOUSE_ID (ou à passer en 3e argument)
npx @databricks/appkit generate-types [rootDir] [outFile] [warehouseId]

Exemples

  • Générer les types à partir de l'ID de warehouse défini dans l'environnement

    npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts
  • Générer les types en spécifiant explicitement l'ID de warehouse

    npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts abc123...
  • Forcer la régénération (ignorer le cache)

    npx @databricks/appkit generate-types --no-cache

Disponibilité du warehouse et l'option --wait

Par défaut, generate-types est non bloquant : il n'attend jamais votre SQL warehouse et n'échoue jamais à cause de celui-ci. Il écrit immédiatement les meilleurs types possibles (en réutilisant les types mis en cache lorsque la requête est inchangée, sinon result: unknown), puis lance un worker d'arrière-plan détaché qui actualise les types réels dès que le warehouse est prêt. npm install (postinstall) et npm run dev (predev) restent ainsi rapides et résilients face à un warehouse froid ou momentanément inaccessible. Le plugin Vite de développement se comporte de la même manière : les types apparaissent instantanément, puis sont actualisés sur place dès que le warehouse est actif.

Utilisez --wait pour les builds de CI et de production, où des types exacts doivent être disponibles avant que le build ne se poursuive :

npx @databricks/appkit generate-types --wait

Résilience en CI : les types commités comme solution de repli

En mode bloquant (--wait), le générateur tente de récupérer les types réels depuis votre warehouse, mais se rabat sur les fichiers de types commités (shared/appkit-types/analytics.d.ts et, lorsque des Metric Views sont configurées, shared/appkit-types/metric-views.d.ts) lorsque le warehouse est injoignable. Ces fichiers générés doivent faire partie de votre dépôt. Sur un checkout CI neuf, chaque build tente un DESCRIBE sur le warehouse ; les types commités ne servent que si cette opération ne peut aboutir.

Le générateur n'écrase jamais les types commités par des types dégradés (result: unknown) : soit il écrit des types réels, soit il n'écrit rien du tout.

Une taxonomie des échecs en deux catégories détermine si le build échoue ou se rabat sur les types commités :

  • Échecs déterministes (échec systématique) : erreurs de syntaxe SQL dans vos requêtes (véritable échec d'un DESCRIBE sur un warehouse joignable), HTTP 404 (ID de warehouse erroné ou inconnu), HTTP 400 (requête mal formée). Il s'agit d'erreurs de développement ou de configuration que les types commités ne doivent pas masquer.
  • Échecs environnementaux (repli conditionné aux types commités) : échecs d'authentification (401/403), réseau injoignable, warehouse indisponible (froid, en cours de suppression ou supprimé), dépassement du délai d'attente de l'état RUNNING, ou tout échec non reconnu. Si tous les fichiers de types requis par l'application existent, le build les conserve, émet un avertissement bien visible sur stderr et réussit (code de sortie 0). Si un fichier requis est manquant, le build échoue avec un message vous invitant à exécuter npx @databricks/appkit generate-types --wait en local (sur un warehouse joignable) et à commiter les fichiers de types générés.

Cet avertissement tient en une seule ligne sur stderr, facile à filtrer avec grep, indiquant la cause générale (authentification bloquée / warehouse injoignable / warehouse indisponible) ainsi que l'ID du warehouse, afin que les journaux CI signalent clairement que le build s'est rabattu sur les types commités.

Pour une application Metric Views, metric-views.d.ts doit déjà exister pour qu'un échec environnemental puisse se replier correctement : analytics.d.ts seul ne suffit pas à satisfaire la condition.

Le modèle d'application met tout cela en place pour vous : postinstall et predev exécutent le mode non bloquant par défaut, tandis que prebuild exécute --wait.

Types de vues de métriques

generate-types (ainsi que le plugin Vite) émet les types de vues de métriques de façon additive — il n'existe pas de commande distincte. Lorsqu'un fichier config/metric-views/definitions.json est présent, l'exécution qui génère vos types de requêtes applique aussi un DESCRIBE à chaque vue de métriques UC déclarée et écrit deux artefacts :

  • shared/appkit-types/metric-views.d.ts — enrichit l'interface MetricRegistry afin que useMetricView('<key>', …) bénéficie de l'autocomplétion et de la vérification de types. Les mesures, les dimensions et leurs métadonnées sémantiques (type SQL, nom d'affichage, format, granularités temporelles) de chaque vue sont encodées au niveau des types. Les clés de lignes sélectionnées utilisent le type de valeur réellement transmis par JSON_ARRAY (string | null) ; le type SQL reste disponible dans les métadonnées pour un parsing ou un formatage délibérés.
  • config/metric-views/metadata.generated.json — le pendant runtime de cette même passe, qui transporte ces métadonnées par colonne sous forme de valeur, aux côtés de votre definitions.json rédigé à la main. La route de métriques le découvre automatiquement et attache les métadonnées des colonnes demandées à la charge utile de sa réponse : aucun câblage de plugin n'est donc nécessaire. Versionnez-le avec vos types générés ; comme il est généré, ne le modifiez pas à la main.

Si config/metric-views/definitions.json est absent, le chemin des métriques reste inactif (rien n'est émis). S'il est présent, il suit le même contrat de disponibilité du warehouse que les types de requêtes : lors d'une exécution non bloquante par défaut, une vue qui ne peut pas encore être décrite — warehouse à froid, ou source incorrecte/injoignable — est écrite avec des types permissifs et un avertissement, tandis qu'avec --wait, les vues de métriques respectent la taxonomie à deux catégories (les échecs environnementaux basculent vers le metric-views.d.ts versionné avec un avertissement ; les échecs déterministes, comme des définitions mal formées, font échouer le build). Un definitions.json mal formé (JSON invalide, ou source qui n'est pas un FQN UC en trois parties) échoue immédiatement dans tous les modes.

definitions.json est indexé par clé de métrique ; chaque entrée nomme le FQN UC en trois parties de la vue et, éventuellement, l'exécuteur sous lequel elle s'exécute (app_service_principal, la valeur par défaut, ou user) :

{
  "$schema": "https://databricks.github.io/appkit/schemas/metric-source.schema.json",
  "metricViews": {
    "revenue": { "source": "catalog.schema.revenue_metrics" },
    "customers": {
      "source": "catalog.schema.customer_metrics",
      "executor": "user"
    }
  }
}

La ligne facultative $schema active l'autocomplétion dans l'éditeur ainsi que la validation par rapport au schéma publié.

Fonctionnement

Le générateur de types :

  1. Parcourt votre dossier config/queries/ à la recherche de fichiers .sql
  2. Analyse les annotations de paramètres SQL (par exemple, -- @param startDate DATE)
  3. Se connecte à votre SQL Warehouse Databricks pour déduire le type des colonnes de résultat
  4. Génère des interfaces TypeScript pour les paramètres et les résultats des requêtes
  5. Crée un type QueryRegistry permettant une exécution de requêtes typée

Paramètres pendant DESCRIBE QUERY

La génération de types décrit chaque requête sans lier de paramètres réels : elle substitue donc une valeur par défaut fictive à chaque :param (par exemple '' pour une chaîne). Cela casse les requêtes dont la structure dépend d'une valeur — en particulier les noms de tables dynamiques via IDENTIFIER(:catalog || '.schema.table'). Annotez ces paramètres avec une valeur d'exemple (-- @param catalog STRING = main) pour que l'appel describe puisse résoudre une table réelle. Cette valeur d'exemple ne sert qu'au moment de la génération de types : au runtime, la requête lie bien le paramètre réel. Consultez Paramètres SQL → Valeurs d'exemple.

Utiliser les types générés

Une fois les types générés, votre IDE propose l'autocomplétion et la vérification de types :

import { useAnalyticsQuery } from "@databricks/appkit-ui/react";
import { sql } from "@databricks/appkit-ui/js";

// TypeScript sait que "users_list" est une clé de requête valide
// et quels paramètres elle attend
const { data } = useAnalyticsQuery("users_list", {
  status: sql.string("active"),
  limit: sql.number(50),
});

// TypeScript connaît la structure des lignes de résultat
data?.forEach((row) => {
  console.log(row.email); // ✓ l'autocomplétion fonctionne
});

Voir aussi

Databricks Developer Hub

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

Lire la documentation