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.
Basic selection mapping
Given the following 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:
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:
{
"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
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:
{
"result": {
"id": "1",
"name": {
"value": "Lunar Rover Wheels"
},
"specifications": {
"material": "Titanium alloy",
"diameter": "50 cm"
}
}
}
You can "unwrap" fields using the .
prefix:
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:
{ "name": "Lunar Rover Wheels" }
The following selections have the corresponding results:
Selection | Result |
---|---|
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:
{ "name": { "value": "Lunar Rover Wheels" } }
Selection | Result |
---|---|
$.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:
Selection | Result |
---|---|
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:
{
"id": "1",
"brand_id": "2",
"variant_ids": ["3", "4"]
}
You can create the desired structure using curly braces ({}
) and $
:
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:
{
"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:
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}
Example: Complex nested selection
A complex, nested GraphQL type, Product
, maps its fields from a REST endpoint returning multiple nested objects.
See JSON Response
{
"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"
}
]
}
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
Read the other pages in this section to see examples for working with arrays, enums, and literal values.
Refer to the mapping language reference for a complete overview of mapping syntax and usage.