AWS Glue logoAPI

The AWS Glue Integration API, Route by Route

CoreModels models vendor governance as a small, fixed set of verbs and applies them uniformly to every connector. For AWS Glue Data Catalog — vendor key `glue` — that is eight core routes on the interactive surface and two on the machine-to-machine surface. (A newer sync-plan surface — `sync/propose`, plan fetch, and the sync ledger — sits beside these and is not covered here.) This is the reference: the exact paths, the role each one enforces, the request bodies as the API defines them, and the responses you actually get back.

The AWS Glue Integration API, Route by Route

CoreModels models vendor governance as a small, fixed set of verbs and applies them uniformly to every connector. For AWS Glue Data Catalog — vendor key glue — that is eight core routes on the interactive surface and two on the machine-to-machine surface. (A newer sync-plan surface — sync/propose, plan fetch, and the sync ledger — sits beside these and is not covered here.) This is the reference: the exact paths, the role each one enforces, the request bodies as the API defines them, and the responses you actually get back.

Both surfaces authenticate with Authorization: Bearer …. The interactive surface (graph/integrations/…) expects your normal CoreModels login token; the v1 surface accepts user API keys, which is what makes it the right target for pipelines and dashboards. Throughout, https://coremodels.example.com stands in for your API base URL, $TOKEN for the token, and $PROJECT_ID for the 32-character hex project id.

RouteRoleWrites?
GET graph/integrations/vendorsany authenticatedno
POST graph/integrations/glue/import/{projectId}Adminyes — additive only
POST graph/integrations/glue/audit/{projectId}Viewerhistory, only if asked
POST graph/integrations/glue/reaudit/{projectId}Viewerhistory, always
GET graph/integrations/glue/history/{projectId}Viewerno
GET graph/integrations/glue/badge/{projectId}Viewerno
POST graph/integrations/glue/generate/{projectId}Viewerno
GET graph/integrations/glue/status/{projectId}Viewerno
POST v1/{projectId}/integrations/glue/auditViewer (API key)history, only if asked
GET v1/{projectId}/integrations/glue/badgeViewer (API key)no

Three request bodies, reused everywhere

The artifact-bearing routes (import and audit, on both surfaces) share one shape:

{
  "artifacts": { "tables": "<raw contents of tables.json>" },
  "spaces": [],
  "recordHistory": false
}

artifacts maps artifact name to raw content; Glue defines a single name, tables. spaces is optional — an empty array means the project's main space. recordHistory applies to audit only.

Re-audit takes a three-field body, everything optional:

{ "projectName": null, "spaces": null, "notifySlack": false }

notifySlack opts in to a notification on the project's configured Slack webhook when the recorded run carries errors or warnings — like recording, an explicit ask, default false.

Generate takes:

{ "typeNames": [], "targetVersion": null, "extra": {}, "spaces": null }

typeNames restricts generation to named types (empty means everything eligible). targetVersion and extra exist for connectors with dialect switches; the Glue generator reads neither, so for this vendor they are inert.

Discovery

curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://coremodels.example.com/graph/integrations/vendors"

Any authenticated user may call it. The Glue entry is your capability contract:

{
  "key": "glue",
  "displayName": "AWS Glue Data Catalog",
  "capabilities": "Import, Audit, Generate",
  "artifacts": {
    "tables": "required — `aws glue get-tables` JSON (one response, an array of responses, or a bare TableList)"
  }
}

Glue declares all three of Import, Audit and Generate. (A fourth flag, live sync, exists in the capability vocabulary and is deliberately not claimed by any connector — CoreModels never holds your cloud credentials.)

Import — Admin

curl -sS -X POST \
  "https://coremodels.example.com/graph/integrations/glue/import/$PROJECT_ID" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  --data-binary @import-request.json

Import is additive by design: tables become governed Types, columns and partition keys become Elements, vendor metadata is attached — and an already-governed node is never mutated or deleted. Re-import a grown catalog and the new tables land while the familiar ones are counted under datasetsSkippedExisting; new columns on already-governed tables land under fieldsAdded. Drift is not applied here. Drift is the audit's job, and acting on it is a human decision.

The response carries datasetsAdded, datasetsSkippedExisting, fieldsAdded, lineageEdgesAdded, lineageEdgesSkipped, nodesEnriched, a snapshotStored flag, and the lossiness / errors arrays. Errors mean could not proceed; lossiness means proceeded, and here is what was approximated.

Audit — Viewer

curl -sS -X POST \
  "https://coremodels.example.com/graph/integrations/glue/audit/$PROJECT_ID" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  --data-binary @audit-request.json

Read-only. recordHistory: true is the one opt-in write it will make, appending a compact record of the run to the project's rolling trail as bookkeeping — never as governed meaning. The response reports errorCount (greater than zero means governed meaning is violated), warningCount, infoCount, a codes map of finding code to count, driftedObjects, fingerprint (a content hash of the artifact), metrics, the itemized findings, a markdown rendering, historyRecorded, and lossiness.

Re-audit — Viewer

curl -sS -X POST \
  "https://coremodels.example.com/graph/integrations/glue/reaudit/$PROJECT_ID" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{}'

Same engine, different input. The live audit asks "do these fresh artifacts still conform to the governed model?"; re-audit asks "does the governed model still match the last-known estate?" by replaying the audit over the catalog snapshot stored at import time. No artifacts, no AWS access. Pass projectName to target a specific vendor-side database when several have been imported; null uses the most recently stored snapshot. Unlike audit, re-audit always records its run, and the report carries an extra Snapshot stored metric telling you how old that snapshot is.

If no snapshot exists, the call fails with a precise error: No stored estate snapshot for vendor 'glue' — import the vendor project first (imports persist the parsed snapshot).

History — Viewer

curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://coremodels.example.com/graph/integrations/glue/history/$PROJECT_ID"
{
  "success": true,
  "vendor": "glue",
  "projects": [
    {
      "projectName": "lake",
      "runs": [
        {
          "at": "2026-08-04T09:41:07.6620114+00:00",
          "trigger": "ci",
          "errorCount": 0,
          "warningCount": 1,
          "infoCount": 2,
          "codes": { "semi-structured-column": 1, "table-no-description": 1, "classification-missing": 1 },
          "fingerprint": "3f9c1d5a7b2e4086"
        }
      ]
    }
  ]
}

Runs are newest first, grouped per vendor-side database, and the window is capped — the trail is a trend line, not an archive. trigger is one of audit, ci, reaudit, or scheduled.

Badge — Viewer

curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://coremodels.example.com/graph/integrations/glue/badge/$PROJECT_ID" > glue-audit.svg

Returns image/svg+xml: a shields-style badge labeled glue audit, rendered from the latest recorded run. Green is clean, yellow is warnings only, red is errors, gray means no recorded runs yet (you will also get gray for an unrecognized vendor key rather than an error page). A project whose audits never set recordHistory keeps a gray badge forever.

Generate — Viewer

Glue claims the Generate capability, and the artifact is worth having:

curl -sS -X POST \
  "https://coremodels.example.com/graph/integrations/glue/generate/$PROJECT_ID" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{ "typeNames": [] }'
{
  "success": true,
  "artifacts": [
    { "name": "coremodels_glue_tables.sql", "kind": "sql", "content": "-- Generated by CoreModels …" }
  ],
  "lossiness": [],
  "errors": []
}

The content is Athena/Hive DDL built from the governed model:

-- Generated by CoreModels — governed Athena/Glue table definitions.
-- Set the LOCATION per table before running; meaning changes belong in CoreModels.

CREATE EXTERNAL TABLE IF NOT EXISTS events (
    event_id string COMMENT 'Event key.',
    user_id bigint,
    occurred_at timestamp,
    payload struct<action:string,value:double> COMMENT 'Raw payload.'
)
COMMENT 'Raw product events landed from Kinesis.'
PARTITIONED BY (
    event_date date COMMENT 'Partition.'
)
STORED AS PARQUET
LOCATION 's3://<your-bucket>/events/';

Note what rides along: the recorded Hive type is re-emitted verbatim (a struct<…> column comes back as a struct<…> column, not as a degraded string), governed descriptions and taxonomy allowed-values become column COMMENTs, partition-flagged elements are reconstructed into PARTITIONED BY, and the LOCATION is a placeholder you must set — the governed model knows your schema, not your bucket layout.

Two skips are declared rather than silent: governed views (Views are derived objects; DDL generation covers tables only.) and governed types with no elements, both reported as StructuralDrop records in lossiness. If nothing is eligible at all, the call returns success: false with No eligible tables found to generate DDL for.

Status — Viewer

curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://coremodels.example.com/graph/integrations/glue/status/$PROJECT_ID"
{
  "success": true,
  "vendor": "glue",
  "imported": true,
  "state": {
    "vendor": "glue",
    "projectName": "lake",
    "importedAt": "2026-08-04T09:14:22.1043117+00:00",
    "toolVersion": null,
    "artifactVersion": null,
    "generatedAt": null,
    "sourceFingerprint": "3f9c1d5a7b2e4086",
    "counts": "fieldsAdded=0, lineageAdded=0, lineageSkipped=0, nodesEnriched=10",
    "facts": "{\"tables\":\"2\",\"views\":\"0\"}"
  },
  "governedDatasets": 2
}

imported: false with a null state simply means no Glue import has happened in this project. The tool-version, artifact-version and generated-at slots of the state record stay empty for Glue: a get-tables response carries no generator stamp, and we do not fabricate one. facts is the connector's own parser summary — how many tables and how many views it saw.

The machine-to-machine surface

curl -sS -X POST \
  "https://coremodels.example.com/v1/$PROJECT_ID/integrations/glue/audit" \
  -H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
  --data-binary @audit-request.json

Identical request body, one structural difference in the response: it is wrapped in the standard API envelope, so every report field lives under data.*. A pipeline checks data.errorCount, not errorCount. When recordHistory is true here the run is recorded with trigger ci, which keeps automated runs distinguishable from interactive ones in the trail. The badge is available on this surface too, at GET v1/{projectId}/integrations/glue/badge.

What is not here is as important: reaudit and history live on the interactive surface only.

Failure modes worth handling

An unknown vendor key on any route returns success: false with a message that names the alternatives: Unknown vendor 'gluu'. Registered: …. A missing or empty artifact bag returns Body must include 'artifacts': { "<name>": "<content>" } (e.g. manifest for dbt). A payload that parses as JSON but is not shaped like get-tables output fails at the connector with The artifact is valid JSON but not shaped like get-tables output: …, and one with no named tables with No tables found (expected TableList entries).

The posture behind the whole table at the top: import is the only verb that writes governed structure, and even it only adds; audit and generate write nothing at all. That is why a Viewer-scoped key is all your automation ever needs. (One further Admin verb sits on the shared surface — POST graph/integrations/reconcile/{projectId} — which links datasets that two vendor estates govern as the same physical relation; it becomes interesting once Glue is not your only connected estate.)

For a task-shaped walk through the same routes, see the AWS Glue quickstart in the CoreModels documentation.