Overview
We've got more fields to add to our selection based on our schema.
In this lesson, we will:
- Rename fields
- Apply a mapping expression to each object in an array
Renaming fields
Let's revisit the remaining fields on our Product
type.
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
field and—oops, looks like our selection returns description
rather than the tagline
field we actually need.
Not to worry—our JSON data and schema fields don't need to match 1:1. We can adjust for this difference by renaming the field 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.
topProducts: products
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 fields 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 "alias".
Let's apply an alias of tagline
to our description
field. 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 {idnametagline: description}
Great—we've retrieved the data we want, and returned it under a new key. Next up: our last missing Product
field, tags
!
Accessing tags
To resolve the tags
field, we need to return a list of Tag
types. A Tag
consists of two fields, id
and name
.
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": [{ "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 alias.
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 fields within a selection on the tags
field in our mapping.
Back in the mapping playground, let's build this out. Add tags
to the end of the selection.
$.products {idnametagline: descriptiontags}
Great, we see some tags
information flowing through into our Results panel. Now let's make that first tweak we talked about: aliasing 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 field 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
field; let's add it on the next line after id
.
tags {id: tagIdname}
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 mapping expression 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.
type Query {"Returns all products in the database"products: [Product!]!@connect(source: "products"http: { GET: "/pathway-to-add" }selection: """$.products {idnametagline: descriptiontags {id: tagIdname}}""")}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.
Querying 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 field, like tagline
, from our selection?
This creates a deadend for the tagline
field: unless we provide a different @connect
instance that does include tagline
in its selection, the router 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.
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 fields from our selection also eliminates our ability to alias fields, such as returning the description
property as tagline
in our schema.
Practice
Use the following to answer the next question:
{"shipping": {"estimate": "10.99"}}
type Query {product(id: ID!): Product @connect(...)}type Product {# ... other fieldsshippingPriceEstimate: Float}
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 field 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.
Share your questions and comments about this lesson
This course is currently in
You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.