# Objects URL: /docs/guide/objects Define GraphQL object types from your application's data. We'll define a GraphQL type for a giraffe, using a TypeScript interface to describe its data. ### Defining an Object type [#defining-an-object-type] Create `schema.ts` with a builder and a reference for the `Giraffe` type: ```typescript playground example="objects" import SchemaBuilder from '@pothos/core'; interface Giraffe { name: string; birthday: Date; heightInMeters: number; } const builder = new SchemaBuilder({}); const GiraffeRef = builder.objectRef('Giraffe'); ``` The interface describes the **backing model**: the data returned by resolvers for this type. `objectRef` associates that model with the GraphQL name `Giraffe`. We can use the ref when defining fields that return a giraffe. ### Add some fields [#add-some-fields] Next, call `implement` to define the object's fields. It accepts the options for the object type, including an optional description: ```typescript playground example="objects" GiraffeRef.implement({ description: 'A giraffe in the zoo.', fields: (t) => ({ name: t.exposeString('name'), height: t.exposeFloat('heightInMeters'), birthYear: t.int({ resolve: (giraffe) => giraffe.birthday.getUTCFullYear(), }), }), }); ``` The `fields` function receives a field builder, usually named `t`. Here, `t.exposeString('name')` reads the `name` property from the backing model. The `height` field reads `heightInMeters`, giving that property a different name in the GraphQL schema. For `birthYear`, we write a resolver that computes an integer from the giraffe's birthday. Pothos infers the resolver's first argument as `Giraffe` from the ref. The backing model and GraphQL fields can have different shapes. Clients can query `name`, `height`, and `birthYear`; `birthday` is available to resolvers but isn't exposed as a field. We can add computed fields without adding properties to the backing model. The [fields guide](./fields) covers more field options. For a smaller example of mapping data to a different API shape, try [converting a stored height in meters to feet](/playground?example=foundations-overview). ## Add a query [#add-a-query] Add a field to the root `Query` type that returns a giraffe, then build the schema: ```typescript playground example="objects" builder.queryType({ fields: (t) => ({ giraffe: t.field({ type: GiraffeRef, resolve: () => ({ name: 'James', birthday: new Date(Date.UTC(2012, 11, 12)), heightInMeters: 5.2, }), }), }), }); export const schema = builder.toSchema(); ``` The `type: GiraffeRef` option tells Pothos to check that the resolver returns data matching the `Giraffe` interface. That returned object becomes the first argument to the resolvers for `name`, `height`, and `birthYear`. You can run this schema immediately with a Playground action above. To run it in your own application, add the server below. ### Create a server [#create-a-server] `builder.toSchema()` builds a standard `GraphQLSchema`. To serve it with `graphql-yoga`, install `graphql-yoga` and save this as `server.ts` alongside `schema.ts`: ```typescript import { createServer } from 'node:http'; import { createYoga } from 'graphql-yoga'; import { schema } from './schema'; const yoga = createYoga({ schema }); const server = createServer(yoga); server.listen(3000); ``` ### Query your data [#query-your-data] Run `npx tsx server.ts`, then open [http://localhost:3000/graphql](http://localhost:3000/graphql) and run this query: ```graphql playground example="objects" query { giraffe { name birthYear height } } ``` The result is: ```json { "data": { "giraffe": { "name": "James", "birthYear": 2012, "height": 5.2 } } } ``` ## Different ways to define Object types [#different-ways-to-define-object-types] This guide uses object refs with a TypeScript interface. You can also use an existing class or register backing models by name on the builder. These forms can be used together in the same schema. Object refs Classes SchemaTypes ```typescript playground example="objects" import SchemaBuilder from '@pothos/core'; interface Giraffe { name: string; birthday: Date; heightInMeters: number; } const builder = new SchemaBuilder({}); const GiraffeRef = builder.objectRef('Giraffe'); GiraffeRef.implement({ description: 'A giraffe in the zoo.', fields: (t) => ({ name: t.exposeString('name'), height: t.exposeFloat('heightInMeters'), birthYear: t.int({ resolve: (giraffe) => giraffe.birthday.getUTCFullYear(), }), }), }); ``` ```typescript playground example="objects-variant-classes" class Giraffe { constructor( public name: string, public birthday: Date, public heightInMeters: number, ) {} } builder.objectType(Giraffe, { name: 'Giraffe', fields: (t) => ({ name: t.exposeString('name'), height: t.exposeFloat('heightInMeters'), birthYear: t.int({ resolve: (giraffe) => giraffe.birthday.getUTCFullYear(), }), }), }); ``` ```typescript playground example="objects-variant-builder-types" interface SchemaTypes { Objects: { Giraffe: Giraffe }; } const builder = new SchemaBuilder({}); builder.objectType('Giraffe', { fields: (t) => ({ name: t.exposeString('name'), height: t.exposeFloat('heightInMeters'), birthYear: t.int({ resolve: (giraffe) => giraffe.birthday.getUTCFullYear(), }), }), }); ``` ### Using Refs [#using-refs] You can create and implement a ref in one expression: ```typescript playground example="objects-variant-inline-refs" const GiraffeRef = builder.objectRef('Giraffe').implement({ description: 'A giraffe in the zoo.', fields: (t) => ({ name: t.exposeString('name'), height: t.exposeFloat('heightInMeters'), birthYear: t.int({ resolve: (giraffe) => giraffe.birthday.getUTCFullYear(), }), }), }); ``` For types that reference each other, TypeScript may need ref creation and `implement` to be separate statements, as in the walkthrough above. See [circular references](./circular-references) for details. You can also pass a ref to `builder.objectType(GiraffeRef, { ... })` with the same options. ### Using classes [#using-classes] If your app already represents its data with classes, prefer using those classes as backing models. Pass the class to `builder.objectType`: its instance type becomes the backing model, and the class itself can be used as a field's `type`: The Classes tab shows this definition. Its playground uses `type: Giraffe` in the query field and returns a `new Giraffe(...)` instance. The `name` option supplies the GraphQL type name. When resolving an [interface](./interfaces) or [union](./unions), you can also use an explicit `isTypeOf: (value) => value instanceof Giraffe` option to identify instances of the class. ### Using SchemaTypes [#using-schematypes] You can declare backing models in `SchemaTypes` and pass it to `SchemaBuilder`. This lets you reference object types by their GraphQL names instead of importing refs. Using the `Giraffe` interface from above: The SchemaTypes tab shows the registration. Its playground uses `type: 'Giraffe'` in the query field. The `Objects` mapping tells Pothos which backing model belongs to each name. Here, it types the `Giraffe` field resolvers and checks the object returned by the `giraffe` query. You still define the GraphQL fields with `builder.objectType`; declaring a backing model doesn't expose its properties. The [SchemaBuilder guide](./schema-builder) covers the other type settings.