Mapping Fields

Transform JSON response fields to match your GraphQL schema structure


When mapping REST API responses to GraphQL fields, you'll often need to transform data structures to match your schema. This guide shows common patterns for mapping fields from JSON responses to your GraphQL schema, including renaming, wrapping, and unwrapping fields.

tip
Check out the Connectors Mapping Playground to experiment with and troubleshoot mapping expressions.

Basic selection mapping

Given the following JSON response:

JSON
JSON Response
{
  "id": 1,
  "name": "Lunar Rover Wheels",
  "description": "Innovatively designed wheels for lunar rovers, built to endure harsh moon terrain and provide optimal agility. Each wheel is constructed using advanced materials to withstand temperature fluctuations and dust."
}

You can create a basic, flat GraphQL type with fields that map to REST endpoint fields of the same names:

GraphQL
Example: basic selection
type Query {
  product(id: ID!): Product
    @connect(
      source: "ecomm"
      http: { GET: "/products/{$args.id}" }
      # The REST endpoint returns "id", "name", and "description"
      # in its response, and they're mapped directly to fields of
      # the same name in the GraphQL schema.
      selection: "id name description"
    )
}

type Product {
  id: ID!
  name: String!
  description: String!
}

Renaming fields

Given the following JSON response:

JSON
JSON Response
{
  "product_id": "1",
  "title": "Lunar Rover Wheels"
}

You can map a JSON response field to a schema field of a different name using the same syntax as GraphQL aliases. The desired name (the one present in the schema type) comes first followed by a colon (:) and the name of the field in the response: desiredName: original_name

GraphQL
Example: renaming fields
type Query {
  product(id: ID!): Product
    @connect(
      source: "ecomm"
      http: { GET: "/products/{$args.id}" }
      selection: """
      id: product_id
      name: title
      """
    )
}

type User {
  id: ID!
  name: String!
}

Unwrapping fields

Suppose the JSON response includes nesting that you don't need in your schema:

JSON
JSON Response
{
  "result": {
    "id": "1",
    "name": {
      "value": "Lunar Rover Wheels"
    },
    "specifications": {
      "material": "Titanium alloy",
      "diameter": "50 cm"
    }
  }
}

You can "unwrap" fields using the . prefix:

GraphQL
Example: unwrapping
type Query {
  product(id: ID!): Product
    @connect(
      source: "ecomm"
      http: { GET: "/products/{$args.id}" }
      selection: """
      $.result {
        id
        name: name.value
        $.specifications {
          material
          diameter
        }
      }
      """
    )
}

type Product {
  id: ID!
  name: String!
  material: String
  diameter: String
}

Using $ when unwrapping

A leading $. is required when unwrapping a single property. Without $., it is interpreted as mapping the field to create an object. With $., it is interpreted as mapping the value.

For example, given the following JSON:

JSON
{ "name": "Lunar Rover Wheels" }

The following selections have the corresponding results:

SelectionResult
name{ "name": "Lunar Rover Wheels" }
$.name"Lunar Rover Wheels"
product_name: name{ "product_name": "Lunar Rover Wheels" }

When selecting a path of properties, such as name.value, the $. is allowed but not required:

JSON
{ "name": { "value": "Lunar Rover Wheels" } }
SelectionResult
$.name.value"Lunar Rover Wheels"
name.value"Lunar Rover Wheels"
$.name { value }{ "value": "Lunar Rover Wheels" }
name { value }{ "name": { "value": "Lunar Rover Wheels" } }

The simple form also applies when using value transformations. These are equivalent:

SelectionResult
name->match(["Lunar Rover Wheels", "Wheels"], ["Zero-Gravity Moon Boots", "Boots"]){ "name": "Wheels" }
$.name->match(["Lunar Rover Wheels", "Wheels"], ["Zero-Gravity Moon Boots", "Boots"]){ "name": "Wheels" }

Wrapping fields

You can create nested fields from a flat structure using a variation on the alias syntax. This is especially useful for converting a simple foreign key into an entity reference. If the foreign keys are in a list, you can use the $ symbol to refer to items in the list.

For example, given the following JSON response:

JSON
JSON Response
{
  "id": "1",
  "brand_id": "2",
  "variant_ids": ["3", "4"]
}

You can create the desired structure using curly braces ({}) and $:

GraphQL
Example: wrapping fields
type Query {
  user(id: ID!): Product
    @connect(
      source: "ecomm"
      http: { GET: "/products/{$args.id}" }
      selection: """
      id
      brand: { id: brand_id }
      variants: $.variant_ids { id: $ }
      """
    )
}

type Product {
  id: ID!
  brand: Brand
  variant: [Variant]
}

type Brand {
  id: ID!
}

type Variant {
  id: ID!
}

Accessing fields that start with a numerical value

Field names that start with a numerical value must be put in quotes (" ").

For example, given the following JSON response that includes a specifications.3DModel field:

JSON
JSON Response
{
  "id": 1,
  "name": "Lunar Rover Wheels",
  "specifications": {
    "material": "Titanium alloy",
    "diameter": "50 cm",
    "3DModel": "https://example.com/lunar-rover-wheel-3d"
  }
}

You can map the field like so:

GraphQL
Example: field name with numeric starting character
1type Query {
2  product(id: ID!): Product
3    @connect(
4      source: "ecomm"
5      http: { GET: "/products/{$args.id}" }
6      selection: """
7      id
8      modelUrl: specifications."3DModel"
9      """
10    )
11}
12
13type Product {
14  id: ID!
15  modelUrl: String
16}
note
This example also unwraps and renames the specifications.3DModel field to top-level modelUrl field.

Example: Complex nested selection

A complex, nested GraphQL type, Product, maps its fields from a REST endpoint returning multiple nested objects.

See JSON Response
JSON
{
  "id": 1,
  "name": "Lunar Rover Wheels",
  "createdAt": 1675200000000,
  "updatedAt": 1675200000000,
  "description": "Innovatively designed wheels for lunar rovers, built to endure harsh moon terrain and provide optimal agility. Each wheel is constructed using advanced materials to withstand temperature fluctuations and dust.",
  "slug": "lunar-rover-wheels",
  "tags": [
    { "tagId": "1", "name": "Instruments" },
    { "tagId": "2", "name": "Space" }
  ],
  "category": "Engineering Components",
  "availability": "AVAILABLE",
  "variants": [
    {
      "name": "Standard Wheel",
      "price": {
        "original": 4999,
        "discounts": [],
        "final": 4999
      },
      "specifications": {
        "Material": { "value": "Titanium alloy" },
        "Diameter": { "value": "50 cm" }
      },
      "inventory": { "quantity": 100, "sellUnavailable": false },
      "variantId": "variant1"
    }
  ]
}
GraphQL
1type Query {
2  product(id: ID!): Product
3    @connect(
4      http: { path: "https://ecommerce.demo-api.apollo.dev/products/{$args.id}" }
5      selection: """
6      id
7      name
8      description
9      availability
10      createdAt
11      updatedAt
12      tags: $.tags {
13        id: tagId
14        name
15      }
16      variants: $.variants {
17        name
18        taxable
19        price {
20          original
21          final
22        }
23        specifications: $.specifications {
24          material: Material.value
25          diameter: Diameter.value
26        }
27        inventory {
28          quantity
29          sellUnavailable
30        }
31      }
32      """
33    )
34}
35
36type Product {
37  id: ID!
38  name: String!
39  createdAt: Float
40  updatedAt: Float
41  description: String!
42  availability: String!
43  tags: [Tag]
44  variants: [Variant]
45}
46
47type Tag {
48  id: ID!
49  name: String!
50}
51
52type Variant {
53  name: String!
54  price: Price
55  specifications: Specifications
56  inventory: Inventory
57}
58
59type Price {
60  original: Int
61  final: Int
62}
63
64type Specifications {
65  material: String
66  diameter: String
67}
68
69type Inventory {
70  quantity: Int
71  sellUnavailable: Boolean
72}

Additional resources

Feedback

Ask Community