Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Power BI is turning 10! Let’s celebrate together with dataviz contests, interactive sessions, and giveaways. Register now.

Reply
Syndicate_Admin
Administrator
Administrator

Uso de la API REST de Jira como fuente de datos no dinámica con paginación, filtro, campos y autorización

Hola a todos,

Dado que me llevó mucho tiempo resolver mi problema y finalmente lo logré con esta comunidad, no quería ocultarles la solución y mostrarles cómo logré obtener datos en Power BI a través de la API de Jira Rest. Espero que ayude a muchos otros que tienen el mismo problema y sienten que están buscando en toda la web y no pueden encontrar una solución adecuada, como yo. Sobre la situación inicial. Quería obtener datos de Jira de mi empresa en Power BI a través de la API de Rest. Esto me planteó varios desafíos:

  • El filtro personalizado de Jira generaba >5000 filas de datos. Una llamada en Jira está limitada a un máximo de 1000 resultados. Por lo tanto, el código m tenía que contener una paginación
  • Tuve que definir ciertos campos que eran relevantes para mí y no extraer todos los datos de Jira
  • El encabezado tenía que contener un token de API como autorización, ya que es un Jira de mi organización
  • El origen de datos debe ser estático, de lo contrario, recibí el mensaje de error del origen de datos dinámicos en Power BI Services cuando se debe publicar el informe.

El mayor problema resultó ser el mensaje de error constante de un origen de datos dinámico en Power BI Services. Para solucionar esto utilizo los comandos Web.Contents, RelativePath y Query. Estos artículos me han ayudado mucho como base para entender:
https://blog.crossjoin.co.uk/2016/08/16/using-the-relativepath-and-query-options-with-web-contents-i...
https://blog.crossjoin.co.uk/2016/08/23/web-contents-m-functions-and-dataset-refresh-errors-in-power...

Para obtener el token de API de Jira, sigue este artículo:
https://support.atlassian.com/atlassian-account/docs/manage-api-tokens-for-your-atlassian-account/
A pesar de los blogs que encontré en Internet, una autorización básica no funcionó para mí. Utilicé el tipo de autorización del portador con mi token de API sin modificar.

Para obtener solo los datos de mi filtro personalizado de Jira, el ID del filtro era importante. Puedes averiguarlo en la url de Jira cuando llames al filtro.


En pocas palabras, aquí está la consulta final que funcionó bien para mí y resolvió todos mis desafíos. He tratado de explicar los pasos individuales en los comentarios:

let 
    BaseUrl = 
    Web.Contents(
        "https://XXX.XXX.net/jira/rest/api",
        [
            RelativePath="2/search",
            Query=
            [
                jql="filter=525545",
                fields="issuetype,key,summary,customfield_10401,labels,customfield_10000,status,resolution,customfield_11200"
            ],
            Headers=[Authorization="Bearer **Your Token here**"]]
    )  ,
    // JiraIDPerPage: Number of Jira tickets per page. 
    JiraIDPerPage = 1000,

    // GetJson: Function to retrieve data from the Jira API and return it as JSON.
    GetJson = (Url) =>
        let 
            RawData = Web.Contents(
        "https://XXX.XXX.net/jira/rest/api",
        [
            RelativePath="2/search",
            Query=
            [
                jql="filter=525545",
                fields="issuetype,key,summary,customfield_10401,labels,customfield_10000,status,resolution,customfield_11200"
            ],
            Headers=[Authorization="Bearer **Your Token here**"]]
    )  ,
            Json    = Json.Document(RawData)
        in  Json,

    // GetJiraIDCount: Function to determine the total number of available Jira tickets for a filter ID.
    GetJiraIDCount = () =>
        let Url   = Web.Contents(
        "https://XXX.XXX.net/jira/rest/api",
        [
            RelativePath="2/search",
            Query=
            [
                jql="filter=525545",
                fields="issuetype,key,summary,customfield_10401,labels,customfield_10000,status,resolution,customfield_11200"
            ],
            Headers=[Authorization="Bearer **Your Token here**"]]
    )  ,
            Json  = GetJson(Url),
            Count = Json[#"total"]
        in  Count,

//GetPage function: Retrieves a page of Jira tickets based on the specified index.
// - Index: The page number, starting at 0.
// - Skip: Skips a certain number of Jira tickets based on the page number.
// - Top: Specifies the maximum number of tickets to return per page.
// - Url: The full URL for the API request based on BaseUrl, Skip and Top.
// - Json: Retrieves data from the Jira API and returns it as JSON.
// - Value: Extracts the relevant information (under 'issues') from the JSON.
    GetPage = (Index) =>
    let
        Skip = Text.From(Index * JiraIDPerPage),
        Top = Text.From(JiraIDPerPage),
        PageData = Web.Contents(
            "https://XXX.XXX.net/jira/rest/api",
            [
                RelativePath="2/search",
                Query=
                [
                    jql="filter=525545",
                    startAt=Skip,
                    maxResults=Top,
                    fields="issuetype,key,summary,customfield_10401,labels,customfield_10000,status,resolution,customfield_11200"
                ],
                Headers=[Authorization="Bearer **Your Token here**"]
            ]
        ),
        Json = Json.Document(PageData),
        Value = Json[#"issues"]
    in Value,

    // JiraIDCount: Calculates the total number of Jira tickets and selects the maximum number per page.
    JiraIDCount = List.Max({ JiraIDPerPage, GetJiraIDCount() }),

    // PageCount: Calculates the total number of pages based on the number of tickets per page.
    PageCount   = Number.RoundUp(JiraIDCount / JiraIDPerPage),

    // PageIndices: List of page indices.
    PageIndices = { 0 .. PageCount - 1 },

    // Pages: Retrieves the corresponding page of Jira tickets for each page index.
    Pages       = List.Transform(PageIndices, each GetPage(_)),

    // JiraID: Combines the pages into a complete list of Jira tickets.
    JiraID    = List.Union(Pages),

    // Table: Creates a Power Query table from the list of Jira tickets.
    Table       = Table.FromList(JiraID, Splitter.SplitByNothing(), null, null, ExtraValues.Error),

    //From here data transformation
....

¡Espero que este post te ayude!
Alina

6 REPLIES 6
Syndicate_Admin
Administrator
Administrator

Hola Alina, intenté usar tu código y recibo el error Token Identifier esperado. ¿Es porque no agregué ninguna transformación de datos debajo del código que proporcionó?

Syndicate_Admin
Administrator
Administrator

¡Hola!

La integración de Jira y Power BI puede ser un desafío, pero afortunadamente, puede usar dos métodos principales para lograrlo. Una opción es la API REST de Jira, que requiere habilidades técnicas y puede ser compleja. La segunda opción es Conector de Power BI para Jira.
Es una aplicación fácil de usar que permite exportar datos de Jira a Power BI sin necesidad de conocimientos de codificación. Obtenga más información sobre el segundo método aquí:

https://marketplace.atlassian.com/apps/1221150/power-bi-connector-for-jira?hosting=cloud&tab=overvie... está disponible para Jira Cloud / Server / Data Center.

Dar

Syndicate_Admin
Administrator
Administrator

Hola Alina,

Gracias por el código que proporcionaste.

Desafortunadamente, la consulta devuelve solo 100 filas.

¿Sabrías la razón?

Gracias

Tuve el mismo problema, pero pude resolverlo configurando JiraIDPerPage en 100 (no en 1000).

Hola @HerbertMattos

¿Podría proporcionar el código?

Syndicate_Admin
Administrator
Administrator

Hola @Alina12,

Gracias por compartir, creo que este código de muestra ayudará a otros que tengan el requisito similar.

Saludos

Xiaoxin Sheng

Helpful resources

Announcements
June 2025 Power BI Update Carousel

Power BI Monthly Update - June 2025

Check out the June 2025 Power BI update to learn about new features.

June 2025 community update carousel

Fabric Community Update - June 2025

Find out what's new and trending in the Fabric community.

Top Solution Authors