Return Data from backend

I’m having trouble returning data from an API call on the backend in Bubble. My API lists subscription charges and returns a JSON with several nested objects, including an array called split. When I make this call on the client side, all data returns correctly. However, when I run this call on the backend and pass the response to the client, some fields come through as blank — specifically, the objects within split.

I noticed that if I remove the [] brackets from the split array in the JSON, the data appears on the backend, but this changes the JSON structure, which is not what I want. My goal is to keep the split array and all nested objects within a single backend response, so the client receives everything properly formatted.

Here is an example of the full JSON that the API returns:

{
  "object": "list",
  "hasMore": false,
  "totalCount": 1,
  "limit": 50,
  "offset": 0,
  "data": [
    {
      "object": "payment",
      "id": "pay_yisjdasio12012",
      "dateCreated": "2024-10-23",
      "customer": "cus_000005320924",
      "subscription": "sub_bdqyg71gs718",
      "value": 12.6,
      "netValue": 11.74,
      "description": "Plano Top",
      "billingType": "CREDIT_CARD",
      "creditCard": {
        "creditCardNumber": "0280",
        "creditCardBrand": "MASTERCARD"
      },
      "status": "REFUNDED",
      "dueDate": "2024-10-23",
      "invoiceUrl": "https:/url.com",
      "split": [
        {
          "id": "523422b-9328e-4938f-80c7-cbfas872dac",
          "walletId": "dc408b19-f36c-4619-ae58-8hjyg27d",
          "fixedValue": 1.99,
          "percentualValue": 5,
          "totalValue": 2.57,
          "status": "CANCELLED"
        }
      ],
      "refunds": [
        {
          "dateCreated": "2024-10-30 17:07:56",
          "status": "DONE",
          "value": 12.6
        }
      ]
    }
  ]
}

I’d like to keep this full JSON structure so that split and refunds (and any other nested objects) are displayed correctly on the client side when the call is made through the backend. Has anyone experienced a similar thing? Is there a way to force Bubble to keep nested objects intact on the backend?

Thanks for any help!

Hi @imad30 ,

To keep the original JSON structure with all nested objects, I’m returning the received JSON as another content-type (application/json) in the “Return data from API” step. Inside the body, I’m recreating the JSON structure that I’m getting from the external call.

I don’t know if this approach is the only solution, and it’s certainly not the most elegant one, but it works for me.

1 Like

Hi, @marpas!
Thank you very much for your answer and example, I will try to reproduce it with some calls to try to get the same result. I had already tried a similar approach, but it had not worked. I think that now with your example, it should work.

I will try to reproduce your method in the example below, I will come back to tell you if I succeeded.

{
    "object": "list",
    "hasMore": false,
    "totalCount": 5,
    "limit": 10,
    "offset": 0,
    "data": [
        {
            "id": "b5867112-f68b-4a50-b3a2-7a0b570cbe87",
            "name": "Webhook para assinaturas",
            "url": "https://example.io/version-test/api/1.1/wf/subscriptionwebhook",
            "email": "email@hotmail.com",
            "enabled": true,
            "interrupted": false,
            "apiVersion": 3,
            "authToken": "exampleToken",
            "sendType": "SEQUENTIALLY",
            "events": [
                "SUBSCRIPTION_DELETED",
                "SUBSCRIPTION_UPDATED",
                "SUBSCRIPTION_INACTIVATED",
                "SUBSCRIPTION_CREATED"
            ]
        },
        {
            "id": "3db23d0d-0a0d-4511-97ee-76eca7f57384",
            "name": "Webhook de situação da conta",
            "url": "https://example.io/version-test/api/1.1/wf/statuswebhook",
            "email": "email@hotmail.com",
            "enabled": true,
            "interrupted": false,
            "apiVersion": 3,
            "authToken": "exampleToken",
            "sendType": "SEQUENTIALLY",
            "events": [
                "ACCOUNT_STATUS_GENERAL_APPROVAL_REJECTED",
                "ACCOUNT_STATUS_GENERAL_APPROVAL_PENDING",
               "ACCOUNT_STATUS_GENERAL_APPROVAL_AWAITING_APPROVAL",
                "ACCOUNT_STATUS_GENERAL_APPROVAL_APPROVED",
                "ACCOUNT_STATUS_DOCUMENT_REJECTED",
                "ACCOUNT_STATUS_DOCUMENT_PENDING",
                "ACCOUNT_STATUS_DOCUMENT_AWAITING_APPROVAL",
                "ACCOUNT_STATUS_DOCUMENT_APPROVED",
                "ACCOUNT_STATUS_COMMERCIAL_INFO_REJECTED",
                "ACCOUNT_STATUS_COMMERCIAL_INFO_PENDING",
                "ACCOUNT_STATUS_COMMERCIAL_INFO_AWAITING_APPROVAL",
                "ACCOUNT_STATUS_COMMERCIAL_INFO_APPROVED",
                "ACCOUNT_STATUS_BANK_ACCOUNT_INFO_REJECTED",
                "ACCOUNT_STATUS_BANK_ACCOUNT_INFO_PENDING",
                "ACCOUNT_STATUS_BANK_ACCOUNT_INFO_AWAITING_APPROVAL",
                "ACCOUNT_STATUS_BANK_ACCOUNT_INFO_APPROVED"
            ]
        },
        {
            "id": "08e8f0a7-0df5-4843-a5f3-d1aa1ffe2568",
            "name": "Webhook para transferências",
            "url": "https://example.io/version-test/api/1.1/wf/transferwebhook",
            "email": "email@hotmail.com",
            "enabled": true,
            "interrupted": false,
            "apiVersion": 3,
            "authToken": "exampleToken",
            "sendType": "SEQUENTIALLY",
            "events": [
                "TRANSFER_CANCELLED",
                "TRANSFER_FAILED",
                "TRANSFER_DONE",
                "TRANSFER_BLOCKED",
                "TRANSFER_IN_BANK_PROCESSING",
                "TRANSFER_PENDING",
                "TRANSFER_CREATED"
            ]
        },
        {
            "id": "e10354c2-2ac0-405e-9573-8d80cd21754d",
            "name": "Webhook para notas fiscais",
            "url": "https://example.io/version-test/api/1.1/wf/invoicewebhook",
            "email": "email@hotmail.com",
            "enabled": true,
            "interrupted": false,
            "apiVersion": 3,
            "authToken": "exampleToken",
            "sendType": "SEQUENTIALLY",
            "events": [
                "INVOICE_ERROR",
                "INVOICE_CANCELLATION_DENIED",
                "INVOICE_CANCELED",
                "INVOICE_PROCESSING_CANCELLATION",
                "INVOICE_AUTHORIZED",
                "INVOICE_SYNCHRONIZED",
                "INVOICE_UPDATED",
                "INVOICE_CREATED"
            ]
        },
        {
            "id": "b1d7822f-ba4c-449b-8938-9a7c3e6942cc",
            "name": "Webhook para cobranças",
            "url": "https://example.io/version-test/api/1.1/wf/paymentwebhook",
            "email": "email@hotmail.com",
            "enabled": true,
            "interrupted": false,
            "apiVersion": 3,
            "authToken": "exampleToken",
            "sendType": "SEQUENTIALLY",
            "events": [
                "PAYMENT_CREDIT_CARD_CAPTURE_REFUSED",
                "PAYMENT_CHECKOUT_VIEWED",
                "PAYMENT_BANK_SLIP_VIEWED",
                "PAYMENT_DUNNING_REQUESTED",
                "PAYMENT_DUNNING_RECEIVED",
                "PAYMENT_AWAITING_CHARGEBACK_REVERSAL",
                "PAYMENT_CHARGEBACK_DISPUTE",
                "PAYMENT_CHARGEBACK_REQUESTED",
                "PAYMENT_RECEIVED_IN_CASH_UNDONE",
                "PAYMENT_REFUND_IN_PROGRESS",
                "PAYMENT_REFUNDED",
                "PAYMENT_RESTORED",
                "PAYMENT_DELETED",
                "PAYMENT_OVERDUE",
                "PAYMENT_ANTICIPATED",
                "PAYMENT_RECEIVED",
                "PAYMENT_CONFIRMED",
                "PAYMENT_UPDATED",
                "PAYMENT_CREATED",
                "PAYMENT_REPROVED_BY_RISK_ANALYSIS",
                "PAYMENT_APPROVED_BY_RISK_ANALYSIS",
                "PAYMENT_AWAITING_RISK_ANALYSIS",
                "PAYMENT_AUTHORIZED"
            ]
        }
    ]
}

Thanks again!

No worries. Let me know how it went.

An additional advantage of this method is that you can bypass the 50/100 item limit of things returned by the “Return data from API” action :wink:

1 Like

I think I managed to set up the same structure, at least something similar returns. My only question is that I can’t use this return as data in a group/repeating group, can I?

Because to make it work I’m using the App Connector as an action, with the data it’s not returning, as it’s as if it doesn’t have a defined type. Is that right? Do you make your call on the frontend as an action and display it in the repeating group?



image

About the limits, that’s great to know! It turns out that the API I use only allows a maximum limit of 100 items, but the tip is great for returning items from the bubble database itself.

Thanks again for the help!

I was wrong, I’m not even able to use the return as an action, lol.

I’m using API Connector internal calls for this to utilize its response structure in the frontend. Unfortunately, App Connector also has issues with nested objects

Yes internal Api calls. But if you make your internal call as Data then You can use them in this way

I see, so you connect to your own endpoint instead of using the App Connector.
Is your endpoint set to “GET”?

I will try it that way. Let me see.

If Y like to use them as data source then you can go with GET. Depends what you need.

One more thing. Remove blank spaces when reconstructing your JSON in the backend. Other waybY will get an error in API Connector as bubble will not be able to read your response as valid JSON.

I like to use this https://jsonlint.com/ to check is JSON valid

1 Like

That white space tip was great. I’m having that problem right now.

@marpas, nothing I say will demonstrate my gratitude for your help!

It worked, I followed your steps.

1 - I made the API call to my provider normally;

2 - I used “https://jsonlint.com/” to compress the result without spaces;

3 - In the backend, I created a GET endpoint and made the API call in one of the actions, and as a return, I placed the result obtained in “https://jsonlint.com/”;

4 - I changed the fields of this result to include the results of the first call;

5 - Via API Connector, i made a GET call to the endpoint i had created and now i can use it as data.

Thank you very much! :smiley:

Glad I could help. Cheers👋

1 Like