Telerik blogs

Learn more about GraphQL, including its object types that represent the kind of objects we can fetch from our service and what fields they have.

In some of our past articles, we’ve discussed how to create a GraphQL API in Node.js and how to get started with React and GraphQL. In today’s article, we’ll spend a little time discussing some core concepts of GraphQL APIs—the GraphQL schema and its object types.

As a refresher, GraphQL is a query language for making requests to APIs. With GraphQL, the client tells the server exactly what it needs and the server responds with the data that has been requested. For example, assume we could query the title and price fields on a listing object as follows:

{
  listing {
    title
    price
  }
}

This could return data like the following:

{
  "data": {
    "listing": {
      "title": "Beachfront condo...",
      "price": 50
    }
  }
}

If this were an API we’re working with, how could we know that the listing object has the title and price properties? Does the listing object have more properties we can select? This is where the GraphQL Schema comes in.

Every GraphQL API has a schema that completely describes all the possible data we can request and is the blueprint of a GraphQL API. When a request comes in, it is validated against this schema and processed accordingly.

At the core of every GraphQL schema are the object types, which represent the kind of objects we can fetch from our service and what fields they have.

Object Types

For our previous example above, we had a listing object type, which contains title and price fields. This is how we might define the listing object in a GraphQL schema:

type Listing {
  id: ID!
  title: String!
  address: String!
  price: Int!
}

We’re defining a GraphQL object type named Listing. Within this object, there are several properties:

  • An id property that corresponds to a GraphQL ID.
  • title and address properties, both of which are represented as GraphQL String types.
  • A price property that is characterized as a GraphQL Int.

This syntax is known as the GraphQL Schema Language.

In a GraphQL schema, it’s possible to establish connections between various object types. For instance, the Listing object type might feature a tenant field which itself can be represented as another object type, such as the User object type.

type Listing {
  "..."
  tenant: User!
}

Conversely, the User object type could have a relationship wherein it contains a listing field, representative of the Listing object type.

type User {
  "..."
  listing: Listing!
}

The above illustrates one-to-one connections, signifying that a single listing corresponds to a specific user and vice versa. Additionally, one-to-many connections can be established. An example is the User object type having a listings field, which yields an array of listings.

type User {
  "..."
  listings: [Listing!]!
}

Query and Mutation

In a GraphQL schema, there are two distinct object types named Query and Mutation. A GraphQL schema must contain a Query type, whereas the inclusion of a Mutation type is optional.

Both Query and Mutation act as the primary access points for all GraphQL interactions. The Query type outlines all the available pathways to retrieve data, while the Mutation type specifies the entryways to modify data.

For instance, we might design a Query type to fetch a field termed listings. Similarly, a Mutation type could incorporate a deleteListing field that expects an id parameter.

type Query {
  listings: [Listing!]!
}

type Mutation {
  deleteListing(id: ID!): Listing!
}

The listings query and the deleteListing above are seen to both return variations of the Listing object type.

Scalar Types

In GraphQL, when defining the structure of our data, every attribute of an object will eventually boil down to a fundamental value. This foundational value is represented by what we term scalar types. These are elementary data types that are indivisible—they don’t break down into more specific types or have nested attributes.

By default, GraphQL provides a collection of predefined scalar types:

Boolean

This represents a basic binary choice and can either be true or false.

Int

Denotes a signed 32‐bit whole number. This can range from small to relatively large integers which accommodates most common numeric use cases.

Float

Corresponds to a signed double-precision floating-point figure. In simpler terms, it represents decimal numbers which can be particularly useful when dealing with measurements, monetary values or other precise calculations.

String

Reflects a sequence of characters, encoded in UTF‐8 format. It’s versatile and can hold anything from names to descriptions or even entire articles.

ID

This is a special scalar type, primarily designed to signify unique identifiers for objects. While the underlying idea is that they aren’t primarily meant for human interpretation, in practice, they’re serialized similarly to String. Often, this type aids in fetching specific data entries or ensuring data consistency.

Enumeration Types

Enumeration types, often referred to as enums, are unique scalar types confined to a predefined set of values. For instance, if we were to add a listingType attribute to our previously mentioned Listing object and we want to ensure that this attribute can only assume specific values, we would use an enum type:

enum ListingType {
  HOUSE
  APARTMENT
}

Lists

While objects, scalars and enums represent the core types, we can apply additional modifiers to affect their behavior. Specifically, the use of square brackets in the GraphQL Schema Language allow fields to be defined as lists. Consider this example where we introduce a bookings attribute that returns a list comprising the Booking object type:

type Listing {
  "..."
  bookings: [Booking]
}

Observe the distinction between the [Booking] notation and [Booking!]!. The presence of ! is a mechanism in GraphQL to designate fields as non-nullable. This implies that the field will always resolve to the specified type and will never return a null value.

type Listing {
  "users will always be a non-empty list containing User type elements"
  users: [User!]!

  "bookings might be null, or individual elements in the bookings list might be null"
  bookings: [Booking]
}

This nuanced usage provides a lot of flexibility and precision when shaping the data structure in GraphQL.

Arguments & Input Types

In GraphQL, fields operate similarly to functions in traditional programming languages, where they can accept arguments and return values based on those inputs.

Consider a scenario where we want to supply multiple parameters to a createListing GraphQL mutation field to generate a desired outcome (for instance, to create a listing). Just like how we can provide multiple arguments to a function in languages like JavaScript, we can do the same with a GraphQL field.

type Mutation {
  createListing(
    id: ID!
    title: String!
    address: String!
    price: Int!
  ): Listing!
}

A widely adopted practice in situations like this is to use input object types. In GraphQL’s schema notation, these input types resemble standard object definitions but are prefixed with the input keyword, distinguishing them from regular object types.

For instance, we can define a createListing mutation that mandates a non-nullable argument of CreateListingInput input type.

input CreateListingInput {
  id: ID!
  title: String!
  address: String!
  price: Int!
}

type Mutation {
  createListing(input: CreateListingInput!): Listing!
}

This structure not only makes the schema more readable but also simplifies the process of extending or modifying input parameters in the future.

Wrap-up

GraphQL is a versatile query language that offers great flexibility in requesting and manipulating data. Its schema-based structure ensures a clear contract between clients and servers, enabling the client to have precise control over the data they wish to access. Object types form the cornerstone of this schema facilitating the definition of various data shapes and their interactions.

In some upcoming articles, we’ll discuss and cover some other important GraphQL core concepts such as resolver functions, pagination and caching.


About the Author

Hassan Djirdeh

Hassan is currently a senior frontend engineer at Doordash. Prior to Doordash, Hassan worked at Instacart and Shopify, where he helped build large production applications at-scale. Hassan is also a published author and course instructor and has helped thousands of students learn in-depth fronted engineering tools like React, Vue, TypeScript and GraphQL. Hassan’s non-work interests range widely and, when not in front of a computer screen, you can find him at the gym, going for walks or running through the six.

Related Posts

Comments

Comments are disabled in preview mode.