# 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 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 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. ## Add a query [#add-a-query] Add a field to the root `Query` type that returns a giraffe, then build the schema: ```typescript 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`. ### 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 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. ### Using Refs [#using-refs] You can create and implement a ref in one expression: ```typescript const GiraffeRef = builder.objectRef('Giraffe').implement({ fields: (t) => ({ name: t.exposeString('name'), }), }); ``` 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`: ```typescript class Giraffe { constructor( public name: string, public birthday: Date, public heightInMeters: number, ) {} } builder.objectType(Giraffe, { name: 'Giraffe', fields: (t) => ({ name: t.exposeString('name'), }), }); builder.queryType({ fields: (t) => ({ giraffe: t.field({ type: Giraffe, resolve: () => new Giraffe('James', new Date(Date.UTC(2012, 11, 12)), 5.2), }), }), }); ``` 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: ```typescript interface SchemaTypes { Objects: { Giraffe: Giraffe; }; } const builder = new SchemaBuilder({}); builder.objectType('Giraffe', { fields: (t) => ({ name: t.exposeString('name'), }), }); builder.queryType({ fields: (t) => ({ giraffe: t.field({ type: 'Giraffe', resolve: () => ({ name: 'James', birthday: new Date(Date.UTC(2012, 11, 12)), heightInMeters: 5.2, }), }), }), }); ``` 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.