docs/1.28/get-started/03-build-graphql-servers-with-prisma-GO-g201.mdx
import QueryChooser from 'components/Markdown/QueryChooser' import Collapse from 'components/Markdown/Collapse' import Warning from 'components/Markdown/Warning' import Info from 'components/Markdown/Info'
export const meta = { title: 'Build an App', gettingStartedTitle: 'GraphQL API', position: 3, gettingStartedOrder: 1, nextText: 'Congratulations! 🚀 You made it through the quickstart tutorial and learned how to use Prisma and the Prisma client to build a GraphQL server.', technology: 'go', technologyOrder: 4, articleGroup: 'Build an App', }
On this page, you will learn how to:
You're using gqlgen as a GraphQL server library for this project. gqlgen is also used to generated code based on your GraphQL schema to help you build type-safe GraphQL servers.
Create a new directory and add the gqlgen code generation script to it:
mkdir scripts
touch scripts/gqlgen.go
Now add the following code to gqlgen.go:
// +build ignore
package main
import "github.com/99designs/gqlgen/cmd"
func main() {
cmd.Execute()
}
Finally, update the dependencies of your project:
dep ensure -update
Every GraphQL API is based on a GraphQL schema that specifies all API operations and data structures. The schema is a contract between client and server.
Create your GraphQL schema definition file inside a new directory called server:
mkdir server
touch servers/schema.graphql
Now add the following type definitions to the schema file:
type Query {
publishedPosts: [Post!]!
post(postId: ID!): Post
postsByUser(userId: ID!): [Post!]!
}
type Mutation {
createUser(name: String!): User
createDraft(title: String!, userId: ID!): Post
publish(postId: ID!): Post
}
type User {
id: ID!
email: String
name: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
published: Boolean!
author: User
}
gqlenNext, you'll use gqlgen to scaffold the resolvers for your GraphQL server. You first need to create the config file gqlgen.yml that's used as foundation for the code generation process:
touch gqlgen.yml
Now add the following configuration to it:
schema: server/schema.graphql
exec:
filename: server/generated.go
models:
Post:
model: hello-world/prisma-client.Post
User:
model: hello-world/prisma-client.User
resolver:
# Goal: copy&paste from generated file
filename: tmp/resolver.go
type: Resolver
Finally, use the gqlgen code generation script to create the foundation for your GraphQL server:
go run scripts/gqlgen.go
The files in the generated tmp directory contain empty GraphQL resolvers that you need to implement. First, copy the file into a more appropriate location:
cp ./tmp/resolver.go ./server/
When making changes to your GraphQL schema in the future, you need to run
$ go run scripts/gqlgen.goagain. This will override the files intmpso you can copy and paste the new resolvers into their permanent location inservers/resolvers.go.
Now add proper resolver implementations to resolver.go, replace the entire contents of the file with the following:
package main
import (
"context"
"hello-world/generated/prisma-client"
)
type Resolver struct {
Prisma *prisma.Client
}
func (r *Resolver) Mutation() MutationResolver {
return &mutationResolver{r}
}
func (r *Resolver) Post() PostResolver {
return &postResolver{r}
}
func (r *Resolver) Query() QueryResolver {
return &queryResolver{r}
}
func (r *Resolver) User() UserResolver {
return &userResolver{r}
}
type mutationResolver struct{ *Resolver }
func (r *mutationResolver) CreateUser(ctx context.Context, name string) (*prisma.User, error) {
return r.Prisma.CreateUser(prisma.UserCreateInput{
Name: name,
}).Exec(ctx)
}
func (r *mutationResolver) CreateDraft(ctx context.Context, title string, userId string) (*prisma.Post, error) {
return r.Prisma.CreatePost(prisma.PostCreateInput{
Title: title,
Author: &prisma.UserCreateOneWithoutPostsInput{
Connect: &prisma.UserWhereUniqueInput{ID: &userId},
},
}).Exec(ctx)
}
func (r *mutationResolver) Publish(ctx context.Context, postId string) (*prisma.Post, error) {
published := true
return r.Prisma.UpdatePost(prisma.PostUpdateParams{
Where: prisma.PostWhereUniqueInput{ID: &postId},
Data: prisma.PostUpdateInput{Published: &published},
}).Exec(ctx)
}
type postResolver struct{ *Resolver }
func (r *postResolver) Author(ctx context.Context, obj *prisma.Post) (*prisma.User, error) {
return r.Prisma.Post(prisma.PostWhereUniqueInput{ID: &obj.ID}).Author().Exec(ctx)
}
type queryResolver struct{ *Resolver }
func (r *queryResolver) PublishedPosts(ctx context.Context) ([]prisma.Post, error) {
published := true
return r.Prisma.Posts(&prisma.PostsParams{
Where: &prisma.PostWhereInput{Published: &published},
}).Exec(ctx)
}
func (r *queryResolver) Post(ctx context.Context, postId string) (*prisma.Post, error) {
return r.Prisma.Post(prisma.PostWhereUniqueInput{ID: &postId}).Exec(ctx)
}
func (r *queryResolver) PostsByUser(ctx context.Context, userId string) ([]prisma.Post, error) {
return r.Prisma.Posts(&prisma.PostsParams{
Where: &prisma.PostWhereInput{
Author: &prisma.UserWhereInput{
ID: &userId,
}},
}).Exec(ctx)
}
type userResolver struct{ *Resolver }
func (r *userResolver) Posts(ctx context.Context, obj *prisma.User) ([]prisma.Post, error) {
return r.Prisma.User(prisma.UserWhereUniqueInput{ID: &obj.ID}).Posts(nil).Exec(ctx)
}
Each resolver invokes a method on the Prisma client instance which is called Prisma and attached to the incoming resolver object of r.
There are a few configuration steps left until you can start the server.
Update the package name at the top of generated.go from package server to:
package main
Next, move the index.go script you've been using on the previous pages into the server directory:
mv index.go ./server
Now replace the contents of index.go with the following:
package main
import (
"log"
"net/http"
"os"
"hello-world/generated/prisma-client"
"github.com/99designs/gqlgen/handler"
)
const defaultPort = "4000"
func main() {
port := os.Getenv("PORT")
if len(port) == 0 {
port = defaultPort
}
client := prisma.New(nil)
resolver := Resolver{
Prisma: client,
}
http.Handle("/", handler.Playground("GraphQL Playground", "/query"))
http.Handle("/query", handler.GraphQL(NewExecutableSchema(Config{Resolvers: &resolver})))
log.Printf("Server is running on http://localhost:%s", port)
err := http.ListenAndServe(":"+port, nil)
if err != nil {
log.Fatal(err)
}
}
To start the GraphQL server, run the following command:
go run ./server
The GraphQL API of your application layer now exposes the six operations defined in schema.graphql.
To test these operations, navigate your browser to http://localhost:4000 where a GraphQL Playground is running.
A GraphQL Playground is an interactive GraphQL IDE that lets you explore the operations of GraphQL API. You can click the green SCHEMA-button at the right edge of the Playground window to view the auto-generated documentation for your GraphQL API.
</Collapse>Here are a few sample queries and mutations you can send to explore the API.
<QueryChooser titles={["Create a new User", "Create new draft", "Publish a Post", "Fetch published Posts"]}>
mutation {
createUser(name: "Bob") {
id
}
}
mutation {
createDraft(
title: "GraphQL is great"
userId: "__USER_ID__"
) {
id
published
author {
id
}
}
}
mutation {
publish(id: "__POST_ID__") {
id
title
published
}
}
query {
publishedPosts {
id
title
author {
id
name
}
}
}
In some snippets, you need to replace the
__USER__ID__or__POST_ID__placeholder with the ID of an actual user.