3. Accessing and renaming properties
4m

Overview

We've got more to add to our selection based on our schema.

In this lesson, we will:

  • Rename s
  • Apply a to each object in an array

Renaming fields

Let's revisit the remaining on our Product type.

schema.graphql
type Product {
"The unique identifier for the product"
id: ID!
"The product's name"
name: String!
"The at-a-glance description for a product"
tagline: String!
"The tags applied to the product"
tags: [Tag!]!
}
type Tag {
"The unique identifier for a tag"
id: ID!
"The name for the tag"
name: String!
}

We've accounted for id and name, but we're missing the tags and—oops, looks like our selection returns description rather than the tagline we actually need.

Not to worry—our JSON data and schema don't need to match 1:1. We can adjust for this difference by renaming the we return. And we've actually already seen this process in action!

Let's walk through a quick refresher. In the last lesson, we saw the full expression to return a specific JSON property ($.products) under a corresponding key (products).

products: $.products

We were able to drop the first instance of "products" (along with the colon) because it matched the name of the property we were accessing from the JSON.

But with this same syntax, it would also have been possible for us to return the data under an entirely different key.

Renaming the products field
topProducts: products

A diagram showing how products data could be returned under a new output key called topProducts

Specifying an "output key" allows us to select any property from our JSON and return it under a completely different name. And this comes in handy when the in our JSON differ from the fields we've defined in our schema!

When we apply an output key with a different name from our selection, we can think of it as giving our selection an "".

A diagram showing how to break down aliases with desired name, colon, original name

Let's apply an of tagline to our description . Following our syntax, we start with what we want the field to be called. Then we add a colon (:), and specify the name as it appears in the JSON response. In this case, that's description.

$.products {
id
name
tagline: description
}

A screenshot showing the aliases applied to the description tagline

Great—we've retrieved the data we want, and returned it under a new key. Next up: our last missing Product , tags!

Accessing tags

To resolve the tags , we need to return a list of Tag types. A Tag consists of two , id and name.

schema.graphql
type Product {
# ... other Product fields
"The tags applied to the product"
tags: [Tag!]!
}
type Tag {
"The unique identifier for a tag"
id: ID!
"The name for the tag"
name: String!
}

Let's compare this structure with the "tags" property from one of our product objects.

Tags from a product JSON object
"tags": [
{ "tagId": "9", "name": "puzzle" },
{ "tagId": "10", "name": "space" }
],

This looks almost perfect, with one exception: each tag object has a tagId, rather than the id key that we want. We can fix this with—you guessed it!—an .

But before we jump to it, there's just one other thing to note here: the "tags" property returns an array of objects. We have to be specific about which keys we want to return from each tag object; so, we'll define those within a selection on the tags in our mapping.

Back in the mapping playground, let's build this out. Add tags to the end of the selection.

$.products {
id
name
tagline: description
tags
}

The Mapping panel updated to return each product's tags

Great, we see some tags information flowing through into our Results panel. Now let's make that first tweak we talked about: tagId to id.

To do this, we'll introduce a selection to be applied to each object in the tags array. We can start this selection by adding curly braces ({}) after tags. On the first line, we'll define our key and the it should apply to.

tags {
id: tagId
}

Note: We've included tags without a preceding $. since we want to include the tags key in our output. This is equivalent to writing tags: tags { id: tagId }.

And no change is needed for the name ; let's add it on the next line after id.

tags {
id: tagId
name
}

And with that, we've reformatted our tags to suit the shape of our schema's Tag type.

Applying the mapping selection in the schema

Writing our in the playground is great; but what does this look like when we actually apply our selection in an instance of @connect?

Here's what our implementation might look like applied to the Query.products connector.

schema.graphql
type Query {
"Returns all products in the database"
products: [Product!]!
@connect(
source: "products"
http: { GET: "/pathway-to-add" }
selection: """
$.products {
id
name
tagline: description
tags {
id: tagId
name
}
}
"""
)
}
type Product {
"The unique identifier for the product"
id: ID!
"The product's name"
name: String!
"The at-a-glance description for a product"
tagline: String!
"The tags applied to the product"
tags: [Tag!]!
}
type Tag {
"The unique identifier for a tag"
id: ID!
"The name for the tag"
name: String!
}

This selection returns exactly what we've indicated is possible in our schema.

for products returns a list of Product types; we can select each product's id, name, tagline, and tags, and feel confident that this data source provides it.

But what would happen if we omitted a , like tagline, from our selection?

A diagram showing a selection set that omits tagline, and an error when tagline is included in a query

This creates a deadend for the tagline : unless we provide a different @connect instance that does include tagline in its selection, the won't know where to go to get data for it.

To see these errors in your IDE directly as you write the schema, check out the following reference for federation-specific extensions by IDE.

We'll encounter the same problem if we reduce our selection to return the entire array of products data.

A diagram showing how a selection of just $.products would result in an error from incomplete selection

Though we know from inspecting our REST response that each product object contains an id, name and so on, we need to list these within the selection specifically. Omitting the from our selection also eliminates our ability to fields, such as returning the description property as tagline in our schema.

Practice

Use the following to answer the next question:

JSON Input
{
"shipping": {
"estimate": "10.99"
}
}
Schema
type Query {
product(id: ID!): Product @connect(...)
}
type Product {
# ... other fields
shippingPriceEstimate: Float
}
Given the JSON input and schema above, which of the following would result in a valid mapping for the Query.product selection? (Select all that apply)

Key takeaways

  • To rename a property we select from a JSON response, we can add an output key in front of the property. To do this, we use the syntax: desiredName: originalName.
  • We can use curly braces ({}) after a that returns an object to dig into its keys and select the ones we want to return.
  • When used on an array, the curly braces ({}) allow us to specify the selection that should be applied to each object in the array.

Up next

We've gotten some practice accessing properties, and renaming them to match our schema. Next up, let's jump into the methods that transform our responses.

Previous

Share your questions and comments about this lesson

This course is currently in

beta
. Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.