Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se muestra cómo crear un elemento de mapa Fabric y aplicar una definición de mapa mediante Python. Muestra los patrones de orden de operaciones admitidos e incluye el control de errores básico.
La creación de un mapa de Fabric de forma programática requiere dos componentes.
- Definición de mapa (
map.json) - Elemento mapa en un área de trabajo de Fabric
En función del patrón que elija, puede hacer lo siguiente:
- Cree primero el elemento de mapa y asigne la definición más adelante, o
- Crear el elemento de mapa con la definición insertada en una única solicitud
En este artículo se muestran ambos enfoques.
Sugerencia
En la mayoría de los escenarios de automatización, el enfoque recomendado es crear el mapa con su definición insertada. Esto garantiza que el mapa esté totalmente configurado en el momento de la creación y evite llamadas API adicionales.
Nota:
Este artículo se centra en la creación y configuración del mapa (plano de control). Los datos a los que hace referencia el mapa (como archivos GeoJSON o iconos SVG) ya deben existir en OneLake u otro origen de datos compatible.
Prerrequisitos
- Acceso a un área de trabajo de Fabric
- Microsoft Entra ID identidad de usuario o aplicación con permisos de área de trabajo
- Python 3.9 o posterior
- Un token de acceso de OAuth 2.0 para la API REST de Fabric
Definición de mapa de ejemplo (map.json)
En el ejemplo siguiente se muestra una carga simplificada map.json que:
- Usa el mapa base predeterminado
- Lee los datos de GeoJSON de un origen de datos de Lakehouse.
- Representa los datos como una capa vectorial
La map.json definición es una configuración declarativa que describe:
-
dataSources(por ejemplo, recursos de Lakehouse o Eventhouse que proporcionan datos) -
layerSources(los archivos, tablas o funciones que definen los datos de cada capa) -
layerSettings(la configuración de visualización de cada capa, como colores, iconos o estilos)
La definición describe qué debe representar el mapa, en lugar de definir los pasos de procedimiento para la representación.
map_json = {
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/map/definition/2.0.0/schema.json",
"basemap": {
"options": {
"style": "road"
}
},
"dataSources": [
{
"itemType": "Lakehouse",
"workspaceId": "<workspace-id>",
"itemId": "<lakehouse-item-id>"
}
],
"layerSources": [
{
"id": "points-source",
"name": "Points-GeoJSON",
"type": "geojson",
"itemId": "<lakehouse-item-id>",
"relativePath": "Files/data/points.geojson",
"refreshIntervalMs": 0
}
],
"layerSettings": [
{
"id": "points-layer",
"name": "Points",
"sourceId": "points-source",
"options": {
"type": "vector",
"visible": True,
"color": "#0078D4",
"pointLayerType": "bubble",
"bubbleOptions": {
"color": "#0078D4"
}
}
}
]
}
Para obtener más información sobre los componentes clave de un map.json, vea MapDetails.
Patrón 1: Crear un mapa y asignar la definición
Use este patrón cuando necesite crear primero un elemento de mapa de Fabric y aplicar la definición de mapa más adelante. Este enfoque es útil cuando la definición de mapa se genera dinámicamente, se origina a partir de varios archivos o se actualiza incrementalmente después de que el elemento de mapa ya exista. En este patrón, la llamada API inicial crea el elemento de mapa solo con metadatos y una llamada posterior asigna una definición de map.json válida según el esquema para configurar la cartografía base, los orígenes de datos y las capas.
Nota:
Este patrón se usa normalmente para escenarios avanzados en los que la definición evoluciona con el tiempo o se ensambla dinámicamente.
Paso 1: Crear el elemento de mapa (solo metadatos)
Esta llamada no incluye una definición de mapa:
import httpx
BASE_URL = "https://api.fabric.microsoft.com"
TOKEN = "<access-token>"
WORKSPACE_ID = "<workspace-id>"
map_name = "Automated Map (Pattern 1)"
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
}
# Metadata only – NOT map.json
create_map_payload = {
"displayName": map_name
}
response = httpx.post(
f"{BASE_URL}/workspaces/{WORKSPACE_ID}/items/maps",
headers=headers,
json=create_map_payload,
timeout=30
)
response.raise_for_status()
map_item = response.json()
map_id = map_item["id"]
En este momento, el elemento de mapa existe pero no se aplica ninguna definición.
Paso 2: Definir el mapa (map.json)
Prepare una carga de map_json válida, como el ejemplo mostrado anteriormente.
Paso 3: Asignar la definición al mapa
response = httpx.put(
f"{BASE_URL}/workspaces/{WORKSPACE_ID}/items/maps/{map_id}/definition",
headers=headers,
json={
"definition": {
"parts": [
{
"path": "map.json",
"payload": map_json,
"payloadType": "InlineJson"
}
]
}
},
timeout=30
)
response.raise_for_status()
Patrón 2: Crear el mapa con la definición (recomendado)
Use este patrón para crear y configurar el mapa en una sola operación.
Este enfoque es adecuado para implementaciones declarativas, como canalizaciones de CI/CD o flujos de trabajo de infraestructura como código.
Requisito de Base64
Al incluir una definición en llamadas REST, la carga debe estar codificada en Base64 y proporcionarse como parte de definición.
Importante
Si map.json se incluye en cualquier solicitud REST, debe incluirse como una carga codificada en Base64 en definition.parts[] con payloadType: "InlineBase64".
Asistente de Base64
Use este asistente para convertir un map.json Python dict en la cadena Base64 requerida por definition.parts[].payload.
import base64
import json
def to_inline_base64(obj: dict) -> str:
"""
Serialize a JSON-compatible dict and return a Base64-encoded UTF-8 string.
Use this for definition.parts[].payload when payloadType is InlineBase64.
"""
raw = json.dumps(obj, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
return base64.b64encode(raw).decode("utf-8")
Crea un mapa con definición en línea
La solicitud incluye:
-
displayName(metadatos del elemento de mapa) -
definition.parts[]donde map.json estáBase64-encodedy se marca comoInlineBase64
import httpx
BASE_URL = "https://api.fabric.microsoft.com/v1"
TOKEN = "<access-token>"
WORKSPACE_ID = "<workspace-id>"
map_name = "Automated Map (Pattern 2)"
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json",
}
# Schema-valid map.json (example fields abbreviated here)
map_json = {
"$schema": "https://developer.microsoft.com/json-schemas/fabric/item/map/definition/2.0.0/schema.json",
"basemap": {"options": {"style": "road"}},
"dataSources": [
{
"itemType": "KqlDatabase",
"workspaceId": "<workspace-id>",
"itemId": "<eventhouse-or-kql-db-item-id>"
}
],
"layerSources": [
{
"id": "work-orders-src",
"name": "Work orders (Eventhouse)",
"type": "kusto",
"itemId": "<eventhouse-or-kql-db-item-id>",
"refreshIntervalMs": 5000
}
],
"layerSettings": [
{
"id": "work-orders-layer",
"name": "Work orders",
"sourceId": "work-orders-src",
"options": {"type": "vector", "visible": True, "color": "#0078D4"}
}
]
}
payload = {
"displayName": map_name,
"definition": {
"parts": [
{
"path": "map.json",
"payload": to_inline_base64(map_json),
"payloadType": "InlineBase64"
}
]
}
}
with httpx.Client(timeout=60) as client:
response = client.post(
f"{BASE_URL}/workspaces/{WORKSPACE_ID}/maps",
headers=headers,
json=payload,
timeout=30
)
response.raise_for_status()
created = response.json()
map_id = created["id"]
Resumen: patrón 1 frente a patrón 2 (regla base64)
Ambos patrones de creación de mapas se basan en última instancia en el mismo contrato de definición de mapa, pero difieren en cuándo se proporciona la definición y cuándo se requiere la codificación Base64. En esta sección se vuelve a examinar el patrón 1 y el patrón 2 en paralelo para aclarar una fuente común de confusión: cada vez que map.json se incluye en una llamada REST (ya sea durante la creación o la actualización), se debe proporcionar como parte de la definición codificada en Base64. Comprender esta distinción ayuda a garantizar que los flujos de trabajo de automatización de mapas apliquen el formato de carga correcto en cada paso y eviten errores sutiles de formato de solicitud.
Patrón 1: Crear mapa → luego asignar la definición
- Crear llamada de mapa: solo metadatos (sin definición, por lo que no hay Base64 en tiempo de creación).
- Asignar definición: utilice Update Map Definition con definition.parts[] y payloadType: "InlineBase64" (por lo tanto, Base64 es necesario en el momento de la actualización).
Patrón 2: Creación de un mapa con la definición incluida
-
La llamada para crear un mapa incluye la definición: Debe proporcionar
definition.parts[]y codificar map.json en Base64 mediantepayloadType: "InlineBase64".
Regla general: Si map.json se incluye en cualquier solicitud o respuesta REST, se lleva como una carga base64 en una
definition.parts[]entrada conpayloadType: "InlineBase64".
Creación de una función auxiliar para recuperar el identificador de mapa
Al crear un mapa mediante la API rest de Fabric, la solicitud puede devolver una respuesta aceptada 202. Esto indica que el mapa se está aprovisionando de forma asincrónica como una operación de larga duración (LRO), en lugar de crearse inmediatamente. En este caso, la respuesta no incluye el identificador de mapa y es posible que el endpoint de finalización de LRO no devuelva un resultado utilizable. Además, incluso después de que se complete la operación, es posible que el mapa recién creado no aparezca inmediatamente al llamar a la API Listar Mapas debido a la propagación interna.
Para obtener el identificador de mapa de forma confiable, debe consultar la lista de mapas y volver a intentarlo hasta que el nuevo mapa sea visible. La siguiente función auxiliar implementa este patrón de reintento y garantiza que el flujo de automatización sea resistente a retrasos de aprovisionamiento asincrónicos.
# ---------------------------------------------------------
# Get Map ID
# ---------------------------------------------------------
def resolve_map_id(client, list_url, headers, map_name, max_attempts=10, delay=5):
"""
Resolve the ID of a newly created Fabric map.
Why this function is needed:
- Creating a map may return HTTP 202 (Accepted), indicating an asynchronous
long-running operation (LRO) rather than immediate creation.
- LRO responses for map creation don't always return a resource ID.
- Even after the operation completes, the new map may not be immediately
visible in the List Maps API due to backend propagation delays.
What this function does:
- Repeatedly calls the List Maps API.
- Searches for a map matching the provided display name.
- Retries for a configurable number of attempts with a delay between calls.
Parameters:
client : Authenticated HTTP client
list_url : Maps list endpoint
headers : Authorization headers for Fabric API
map_name : Display name of the map to locate
max_attempts : Maximum number of retry attempts
delay : Delay (seconds) between retries
Returns:
The map ID (string) once the map becomes visible.
Raises:
RuntimeError if the map is not found after all retry attempts.
"""
for attempt in range(max_attempts):
print(f"Resolving map (attempt {attempt + 1}/{max_attempts})...")
resp = client.get(list_url, headers=headers)
resp.raise_for_status()
items = resp.json().get("value", [])
match = next(
(m for m in items if m.get("displayName") == map_name),
None
)
if match:
print("✅ Map found!")
return match["id"]
print("⏳ Map not visible yet. Retrying...")
time.sleep(delay)
raise RuntimeError("Map created but still not visible after retries")
A continuación, en lugar de obtener el ID del mapa como se muestra en el ejemplo anterior (map_id = created["id"]), pruebe:
if response.status_code == 201:
map_id = response.json()["id"]
elif response.status_code == 202:
print("LRO completed via 202. Resolving map by name...")
map_id = resolve_map_id(
client,
create_map_url,
_fabric_headers(),
map_name
)