# Slim Airtable API JSON for a Flutter App

> Airtable returns each row wrapped in records, fields, and metadata, and Flutter decodes all of it on the UI isolate. A RealComposer pipeline injects the Airtable token, asks Airtable for only the columns your ListView renders, and returns just the records array for your Dart model classes.

- Canonical page: https://realcomposer.com/recipes/slim-airtable-json-flutter-app
- Client platform: Flutter
- Upstream services: Airtable
- Category: Payload Slimmer
- JSON version: https://realcomposer.com/recipes/slim-airtable-json-flutter-app.json
- Install in RealComposer (free plan, pre-fills this pipeline): https://realcomposer.com/dashboard/pipelines/new?recipe=slim-airtable-json-flutter-app&via=agent

## Problem: Why raw Airtable responses hurt Flutter performance

Large Airtable tables include attachments, linked record ids, and long text fields the list screen never shows. Decoding that payload on older Android phones causes dropped frames, and the personal access token cannot ship in the app.

- Jank from decoding unused Airtable fields on the UI isolate
- Airtable personal access token embedded in the app
- Attachment metadata downloaded for rows that only show a name and price

## Solution steps

1. **Store credentials in Secret Vault**: Save AIRTABLE_PAT and AIRTABLE_BASE_ID in RealComposer so the value never enters the Flutter project.

2. **Configure the edge pipeline**: Add the upstream steps with vault header injection, set allowed origins, and map only the fields the screen binds.

3. **Decode the slim list in Flutter**: Call your workspace edge URL with a restricted rc_live_ client token.

```
final res = await http.get(
  Uri.parse('https://realcomposer.com/v1/workspace/slim-airtable-json-flutter-app?table=Products'),
  headers: {'Authorization': 'Bearer rc_live_client_token'},
);
final items = (jsonDecode(res.body)['items'] as List).map(Product.fromJson).toList();
```

## Pipeline config

Import this config into a RealComposer pipeline. `{{secrets.NAME}}` values are read from the encrypted Secret Vault at request time, so the client never sees them.

```json
{
  "name": "Slim Airtable API JSON for a Flutter App",
  "method": "GET",
  "cacheTtlSeconds": 120,
  "authMode": "client_token",
  "steps": [
    {
      "stepKey": "airtable",
      "upstreamUrlTemplate": "https://api.airtable.com/v0/{{secrets.AIRTABLE_BASE_ID}}/{{query.table}}?pageSize=50&fields%5B%5D=Name&fields%5B%5D=Price",
      "httpMethod": "GET",
      "headersTemplate": {
        "Authorization": "Bearer {{secrets.AIRTABLE_PAT}}"
      },
      "timeoutMs": 3000
    }
  ],
  "outputMapping": {
    "version": 1,
    "fields": [
      {
        "targetPath": "items",
        "sourceStep": "airtable",
        "sourcePath": "records"
      }
    ]
  }
}
```

## Call the pipeline

```bash
curl -X GET "https://realcomposer.com/v1/workspace/slim-airtable-json-flutter-app" \
  -H "Authorization: Bearer rc_live_client_token"
```

## Payload before and after

Raw upstream response:

```json
{
  "records": [
    {
      "id": "rec8Kx",
      "createdTime": "2026-10-01T12:00:00.000Z",
      "fields": {
        "Name": "Desk Lamp",
        "Price": 49,
        "Photos": [
          {
            "id": "att1",
            "url": "https://dl.airtable.com/lamp.jpg"
          }
        ],
        "Notes": "Long internal description"
      }
    }
  ],
  "offset": "itrA1/rec8Kx"
}
```

Slimmed RealComposer response:

```json
{
  "items": [
    {
      "id": "rec8Kx",
      "createdTime": "2026-10-01T12:00:00.000Z",
      "fields": {
        "Name": "Desk Lamp",
        "Price": 49
      }
    }
  ]
}
```

## FAQ

### Why not use compute() to decode Airtable JSON?

Moving decoding to an isolate avoids jank, but the phone still downloads and parses fields it never shows. Slimming at the edge cuts both bandwidth and parse time.

### Does caching help with Airtable rate limits?

Yes. A short edge TTL lets many app users share one upstream call, which keeps you under the five requests per second base limit.
