Skip to main content
Version: v3.x (DDN)

API Versioning through Field Deprecation

Introduction

As your API grows and adapts to new features or functionality, you might need to adjust its structure. But changing or removing fields in API responses can cause breaking changes. These changes may disrupt client applications that depend on those fields, leading to errors or unexpected behavior.

Hasura supports the @deprecated directive in GraphQL, making it straightforward to mark fields as deprecated. You can include an optional reason to help explain the change, signaling to consumers which fields are outdated or updated.

As an example, imagine we have a type Car with an existing field named engine which is deprecated in favor of motor:

type Car {
id: ID!
make: String!
model: String!
engine: EngineSpec @deprecated(reason: "Use field 'motor' instead")
motor: MotorSpec
}

Consumers of our API will know that engine has been deprecated, why we've deprecated it, and which field to use in its place.

Learn more

You can learn more about this directive in the spec.

Using field deprecation in DDN

The following metadata objects have field deprecation in their GraphQL configuration.

Model

The following example shows how to deprecate a field in a model:

kind: Model
version: V1
definition:
name: Cars
objectType: Car
orderableFields:
- Id
graphql:
selectUniques:
- queryRootField: selectCar
uniqueIdentifier:
- make
- model
deprecated:
reason: Use selectCarById instead
- queryRootField: selectCarById
uniqueIdentifier:
- Id

And the resulting schema:

type Query {
selectCar(make: String!, model: String): Car @deprecated(reason: "use selectCarById instead")
selectCarById(Id: ID!): Car
}

Command

The following example shows how to deprecate a field in a command:

kind: Command
version: V1
definition:
name: GetEngineSpec
outputType: Engine
graphql:
rootFieldName: getEngineSpec
rootFieldKind: Query
deprecated:
reason: "Fuel Engines are no longer supported from Jan 01 2035"

And the resulting schema:

type Query {
getEngineSpec: Engine @deprecated(reason: "Fuel Engines are no longer supported from Jan 01 2035")
}

ObjectType

The following example shows how to deprecate a field in an ObjectType:

kind: ObjectType
version: V1
definition:
name: Car
fields:
- name: Id
type: String
- name: make
type: String
- name: model
type: String
- name: engine
type: String
deprecated:
reason: Use motor field instead
- name: motor
type: String
graphql:
typeName: Car

And the resulting schema:

type Car {
Id: String
make: String
model: String
engine: String @deprecated(reason: "Use motor field instead")
motor: String
}

Relationship

The following example shows how to deprecate a field in a relationship:

kind: Relationship
version: V1
definition:
name: engineSpec
source: Car
target:
command:
name: GetEngineSpec
mapping:
- source:
fieldPath:
- fieldName: engine
target:
argument:
argumentName: name
deprecated:
reason: Engines on cars are no longer supported from Jan 01 2035

And the resulting schema:

type Car {
Id: String
make: String
model: String
engine: String @deprecated(reason: "Use motor field instead")
motor: String
engineSpec: Engine @deprecated(reason: "Engines on cars are no longer supported from Jan 01 2035")
motorSpec: Motor
}

Default deprecation reason

In cases where no deprecation reason is explicitly provided, the @deprecated directive defaults to No longer supported as the reason.

The following example from ObjectType metadata illustrates deprecating a field without specifying a reason.

kind: ObjectType
version: V1
definition:
name: Car
fields:
- name: Id
type: String
- name: make
type: String
- name: model
type: String
- name: engine
type: String
deprecated:
reason: null
- name: motor
type: String
graphql:
typeName: Car

And the resulting schema:

type Car {
Id: String

model: String
engine: String @deprecated(reason: "No longer supported")
motor: String
}