--- title: "Invoke Fabric user data functions (experimental)" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Invoke Fabric user data functions (experimental)} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = FALSE) ``` A Fabric *user data function* is reusable Python code that Fabric hosts and runs. It can accept inputs, perform a task, and return a result. With 'fabricQueryR', an R session can call the published function and receive its structured response. ## Lifecycle The package's User Data Function discovery and invocation APIs are experimental. Their validation, request construction, and response handling are covered by offline tests, and lightweight Core item discovery is exercised against Fabric. However, the package cannot currently maintain repeatable end-to-end coverage for detailed User Data Function discovery and public function invocation. The persistent sandbox is provisioned with a service principal. Microsoft's User Data Function create, update-definition, detailed Get, and delete APIs currently support delegated users, but not service principals or managed identities. The sandbox therefore cannot provision, publish, fully inspect, and remove its own disposable public-function fixtures. Until repeatable end-to-end coverage is possible, treat these APIs and their returned service shapes as subject to change. This guide prepares a function for external use, makes one small call, and then introduces structured parameters and safe retries. Start with a simple function whose output you can verify in the Fabric portal. ## Prepare the function in Fabric In the Fabric portal, publish the user data functions item, switch to *Run only* mode, open the function's properties, enable *Public access*, and copy the *Public URL*. Each function has its own URL. `fabric_user_data_functions()` and `workspace$user_data_functions()` default to `detail = FALSE`. This uses the Core item listing, which supports delegated users, service principals, and managed identities, and returns a read-only `FabricItem` R6 object. `$details()` calls `fabric_item()` to refresh its item record. To force the workload-specific Get API, use `$details(detail = TRUE)` or rediscover with `detail = TRUE`; Microsoft documents that API for delegated users only, not service principals or managed identities. Neither response includes enough information to derive each public function URL, so pass the copied URL to `fabric_function_invoke()`. You could store the URL in an environment variable (rather than hardcoding it): ```{r, eval = FALSE} function_url <- Sys.getenv("FABRIC_FUNCTION_URL") ``` The caller needs Execute permission on the item. A delegated sign-in also needs one Power BI delegated permission. By default, 'fabricQueryR' requests the least-privilege `UserDataFunction.Execute.All` scope. Microsoft also accepts the broader `Item.Execute.All` scope, but it does not replace the caller's item Execute permission. If the app registration grants only that broader scope, select it explicitly: ```{r, eval = FALSE} result <- fabric_function_invoke( function_url, parameters = list(customerName = "Ada", priority = 2L), audience = paste0( "https://analysis.windows.net/powerbi/api/", "Item.Execute.All" ) ) ``` If sign-in succeeds but the call is denied, ask the item owner or Fabric administrator to check item Execute access and the relevant tenant setting. ## Make a first call Parameter names must match the published Python function. For a function with `customerName` and `priority` inputs: ```{r, eval = FALSE} result <- fabric_function_invoke( function_url, parameters = list( customerName = "Ada", priority = 2L ) ) result$status result$output ``` ## Send structured parameters The request body is one named JSON object. Its names must match the published function's camelCase parameters: ```{r, eval = FALSE} structured_result <- fabric_function_invoke( function_url, parameters = list( customerName = "Ada", priority = 2L, lineIds = I(c(101L, 102L)), metadata = list(source = "R", approved = TRUE, note = NULL) ) ) ``` One-element R values normally become JSON scalars. Wrap a one-element value in `I()` when the Python signature expects a list. Named atomic vectors and data frames are also accepted as top-level parameter objects; a named list gives the clearest control over nested JSON shapes. The result is a list which can be inspected: ```{r, eval = FALSE} structured_result$function_name structured_result$invocation_id structured_result$status structured_result$output structured_result$errors structured_result$http_status ``` The response keeps the function status, output, and any structured errors together. Inspect these fields before using the output in a later step. ## Retry only safe functions A function can write data or call another service, so invocation POSTs are not retried by default. If a function is read-only or implements its own durable idempotency key, opt in explicitly: ```{r, eval = FALSE} result <- fabric_function_invoke( function_url, parameters = list(requestId = "stable-business-key"), idempotent = TRUE ) ``` Opted-in calls use bounded retries for transport failures, throttling, and transient HTTP responses. ## Limits Public function calls have request-size, execution-time, and response-size limits. Keep calls focused and pass large data through a Fabric data store instead of function parameters. See the service-limits link below for current values. ## More information See Microsoft's [external invocation tutorial](https://learn.microsoft.com/en-us/fabric/data-engineering/user-data-functions/tutorial-invoke-from-python-app), [programming model](https://learn.microsoft.com/en-us/fabric/data-engineering/user-data-functions/python-programming-model), and [service limits](https://learn.microsoft.com/en-us/fabric/data-engineering/user-data-functions/user-data-functions-service-limits).