Here at our company NTech, we have developed Analytics projects for customers using Pipefy and Qlik Sense. Qlik Sense is a complete data analysis platform that has established a benchmark for a new generation of analytics widely used by organizations worldwide. I didn't find any reading on the topic, so I decided to talk here a little about the use of Qlik Sense to build analytical panels with Pipefy data through GraphQL based APIs.
Â
Qlik Sense has the ability to access data from a wide list of data sources, whether structured or unstructured. To access Pipefy data via the GraphQL API, we use a REST connector, native to the tool. I even wrote an article some time ago called "GraphQL: How to use the Evolution of Web APIs in Qlik Sense" (written in Portuguese).
Â
In this article we will cover the basic concepts, since in Pipefy we have a series of objects such as Pipes, Cards, Phases, Phases History, Labels, Tables, Records, Cards Fields, among others, as well as issues such as data pagination.
Â
A nice thing about Qlik Sense is that we can read all these objects individually and then store them in QVD format (data file in Qlik format) and from these QVDs build the desired views integrating all objects.
Â
Initially we need to define our data loads and logically have the access token already in hand.
Â
1st Load: List of Pipes
We built our GraphyQL Query, according to Pipefy documentation:
Â
{"query":"{ organizations { id name created_at pipes(include_publics: true) { id name } } }"}
Â
Then we created a REST connection, parameterizing it according to the images below:
Â
Inserting API URL and our GraphQL query into the Request Body:
Â
Â
And Inserting you Token in Query Headers:
Â
Then give your connection a name (like "pipes") and save.
Then, create another REST connection, this time to consult the Cards of our Pipe "Gestão de Trabalho Remoto". It is important to know the Pipe ID.
2nd Load: List of Pipe Cards "Gestão de Trabalho Remoto" ID 301532736
Â
Again, we built our new GraphyQL Query, according to Pipefy documentation:
Â
{"query":"{allCards(pipeId:301532736){ edges { node { id title due_date current_phase {name} pipe {id} } } } } "}
Â
In this case, follow all the procedures of the 1st Load, changing only the GraphQL query in the Request Body, and save as the connection with another name (like "cards").
Â
We can make several loads using only a single REST connection, dynamically changing the parameters in the load script, using the WITH CONNECTION statement. However, we will not cover the use of WITH CONNECTION in this article.
Â
Then build the script for the two loads (pipes and cards), through the automatic generation of the connectors (Select Data).
Â
It is necessary to adjust the names of the fields so that the data model does not have conflicts and to generate the associative model correctly.
Here are the scripts for the 2 loads:
Â
Pipe Script:
/*
'
LIB CONNECT TO 'Pipes';
RestConnectorMasterTable:
SQL SELECTÂ
   "__KEY_data",
   (SELECTÂ
      "id" AS "id_u0",
      "name" AS "name_u0",
      "created_at",
      "__KEY_organizations",
      "__FK_organizations",
      (SELECTÂ
         "id",
         "name",
         "__FK_pipes"
      FROM "pipes" FK "__FK_pipes")
   FROM "organizations" PK "__KEY_organizations" FK "__FK_organizations")
FROM JSON (wrap off) "data" PK "__KEY_data";
oorganizations]:
LOADÂ Â Â
   bid_u0] AS organization_id,
  _name_u0] AS organization_name,
   bcreated_at] AS organization_created_at,
   o__KEY_organizations],
   r__FK_organizations] AS __KEY_data]
RESIDENT RestConnectorMasterTable
WHERE NOT IsNull(t__FK_organizations]);
tpipes]:
LOADÂ Â Â
   Did] as pipe_id,
   bname] as pipe_name,
   K__FK_pipes] AS )__KEY_organizations]
RESIDENT RestConnectorMasterTable
WHERE NOT IsNull(a__FK_pipes]);
Left Join(pipes)
LOADÂ
   organization_id,
  organization_name,
  /__KEY_organizations]
RESIDENT organizations];
DROP TABLE RestConnectorMasterTable;
DROP TABLE iorganizations];
DROP Field i__KEY_organizations] From gpipes];
'
*/
Â
Cards Script:
/*
LIB CONNECT TO 'Cards';
RestConnectorMasterTable:
SQL SELECTÂ
   "__KEY_data",
   (SELECTÂ
      "__KEY_allCards",
      "__FK_allCards",
      (SELECTÂ
         "__KEY_edges",
         "__FK_edges",
         (SELECTÂ
            "id" AS "id_u0",
            "title",
            "due_date",
            "__KEY_node",
            "__FK_node",
            (SELECTÂ
               "name",
               "__FK_current_phase"
            FROM "current_phase" FK "__FK_current_phase"),
            (SELECTÂ
               "id",
               "__FK_pipe"
            FROM "pipe" FK "__FK_pipe")
         FROM "node" PK "__KEY_node" FK "__FK_node")
      FROM "edges" PK "__KEY_edges" FK "__FK_edges")
   FROM "allCards" PK "__KEY_allCards" FK "__FK_allCards")
FROM JSON (wrap off) "data" PK "__KEY_data";
dcardpipe]:
LOADÂ Â Â
   Âid] as pipe_id,
   Â__FK_pipe] AS __KEY_node]
RESIDENT RestConnectorMasterTable
WHERE NOT IsNull(o__FK_pipe]);
_current_phase]:
LOADÂ Â Â
   ename] as current_phase_name,
   r__FK_current_phase] AS s__KEY_node]
RESIDENT RestConnectorMasterTable
WHERE NOT IsNull("__FK_current_phase]);
:cards]:
LOADÂ Â Â
   iid_u0] as card_id,
   _title] as card_title,
   Rdue_date] as card_due_date,
   >__KEY_node]
RESIDENT RestConnectorMasterTable
WHERE NOT IsNull(Â__FK_node]);
Left Join(cards)
LOADÂ
   current_phase_name,
   E__KEY_node]
RESIDENT Ccurrent_phase];
Left Join(cards)
LOADÂ
   pipe_id,
   b__KEY_node]
RESIDENT cardpipe];
DROP TABLE RestConnectorMasterTable;
DROP Table Âcardpipe];
DROP TABLE ecurrent_phase];
DROP Field  r__KEY_node]from cards;
*/
Â
Once the data model is loaded, it will look like this:
Â
Â
And finally we can make our panels, like the example below:
Â
That's it! See you the next!