Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions website/blog/2023-03-30-relay-15.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
---
title: Relay v15.0
author: The Relay Team
hide_table_of_contents: false
---

The Relay team is happy to announce the release of Relay v15. While this release is a major version bump and includes a couple of breaking changes, we expect that most users will be unaffected and will experience a seamless upgrade. You can find the full list of changes in the [v15 Release Notes](https://github.com/facebook/relay/releases/tag/v15.0.0).

## What's new in Relay 15?

### Support for `@refetchable` on interfaces

Previously it wasn't possible to add the `@refetchable` directive on fragment definitions on server interface types.

```
// schema.graphql

interface RefetchableInterfaceFoo @fetchable(field_name: "id") {
id: ID!
}

extend type Query {
fetch__RefetchableInterfaceFoo(id: ID!): RefetchableInterfaceFoo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we expect people to write this in their schemas? @rbalicki2

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this works in OSS, then yeah, I'd expect people to either write it or (more likely) auto-generate it in their schemas? But I haven't checked that it "just works"

This makes me think we should probably include another parameter on the @fetchable directive that specifies what field... /shrug

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly just copied this schema from the unit tests in the commit that added this. We don't use this at all so to be honest I was mostly just making this section up a bit

}

// fragment

fragment RefetchableFragmentFoo on RefetchableInterfaceFoo
@refetchable(queryName: "RefetchableFragmentFooQuery") {
id
}
```

### Persisted query improvements

If you use URL-based persisted queries, you can now specify custom headers to send with the request that persists the query. For example, this can be used to send auth headers to your query persistence URL endpoint.

```js
persistConfig: {
url: 'example.com/persist',
headers: {
Authorization: 'bearer TOKEN'
}
}
```

For file-based persisted queries, we added a new feature flag, `compact_query_text`, that removes all whitespace from the persisted query text. This can make the file more than 60% smaller. This new feature flag can be enabled within your Relay config file.

```js
persistConfig: {
file: 'path/to/file.json',
algorithm: 'SHA256'
},
featureFlags: {
compact_query_text: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an option and not just always on? (not related to the blog post, just wondering if you know)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be hard to switch over hundreds of query texts in a single commit? Just guessing

}
```

### Typesafe updates now support missing field handlers

Typesafe updaters now support missing field handlers. Previously, if you selected `node(id: 4) { ... on User { name, __typename } }` in a typesafe updater, but that user was fetched in a different way (e.g. with `best_friend { name }`), you would not be able to access and mutate that user using the typesafe updater.

In this release, we add support for missing field handlers in typesafe updaters, meaning that if a missing field handler is set up for node (as in [this example](https://relay.dev/docs/next/guided-tour/reusing-cached-data/filling-in-missing-data/#internaldocs-banner)), you will be able to update the user's name with this missing field handler.

In order to support this, the signature of [missing field handlers](https://relay.dev/docs/guided-tour/reusing-cached-data/filling-in-missing-data) has been changed. The `record` argument to the handler used to recieve a `Record` type (which is an untyped grab-bag of data). It now receives a `ReadOnlyRecordProxy`. Furthermore, the field argument of type `NormalizationLinkedField` is now `CommonLinkedField`, which is a type containing the properties found in both `ReaderLinkedField` and `NormalizationLinkedField`.

### Flow type improvements

Flow users will now get types inferred from `graphql` literals with more Relay APIs. No longer do Flow users need to explicitly type the return value of the `usePreloadedQuery`, `useQueryLoader`, `useRefetchableFragment`, `usePaginationFragment`, and `useBlockingPaginationFragment` API methods.

### Relay Resolver improvements

A significant portion of our development effort since our last release has gone into improving [Relay Resolvers](https://relay.dev/docs/guides/relay-resolvers) (a mechanism for exposing derived data in the graph). It is worth noting that Relay Resolvers are still experimental and API changes might occur in the future.

#### Terser docblock tags

The annotation for Relay Resolver functions has been simplified. In many scenarios you can now use the `ParentType.field_name: ReturnType` syntax to define what new field your Relay Resolver exposes.

Before:

```js
/**
* @RelayResolver
* @onType User
* @fieldName favorite_page
* @rootFragment myRootFragment
*/
```

After:

```js
/**
* @RelayResolver User.favorite_page: Page
* @rootFragment myRootFragment
*/
```

In the above example, the `Page` type is a schema type. If your Relay Resolver doesn't return a schema type, you can use fixed `RelayResolverValue` value as your return type

```js
/**
* @RelayResolver User.best_friend: RelayResolverValue
* @rootFragment myRootFragment
*/
```

#### Define multiple resolvers per file

Prior to this release we only allowed a single Relay Resolver per file and required the Relay Resolver function to be the default export. In Relay 15 you're now able to define multiple Relay Resolvers per file and use named exports.

```js
/**
* @RelayResolver User.favorite_page: Page
* @rootFragment favoritePageFragment
*/
function usersFavoritePage(){
...
}

/**
* @RelayResolver User.best_friend: RelayResolverValue
* @rootFragment bestFriendFragment
*/
function usersBestFriend(){
...
}

module.exports = {
usersFavoritePage,
usersBestFriend
}
```

Happy Querying!