Skip to main content

Starting Schema

We will be making a group chat app (without the user authentication)

Write a Schema#

Let's look at what the final schema look like:

Feel free to customize the schema to your liking
schema.graphql
type Message {  id: ID!  content: String!  authorName: String!  createdAt: String!}
type Query {  messages(limit: Int! = 30): [Message!]!  messageBy(authorName: String!): [Message!]!}
type Mutation {  send(msg: String!, by: String!): Message!}
type Subscription {  roomLobby: Message!}

Sangria Required Types#

Sangria Schema are written with a required context and root value type. So, let's create a basic context type that can be updated later on.

Stub context case class
Context.scala
case class Context(  // Will be added later)

Sangria Object Types#

I am assumming some sangria knowledge here. Let's create all the proper object types excluding the subscription.

Message Object Type#

Message.scala
import sangria.schema._import sangria.macros.derive._import /*path to file*/.Contextimport java.time.Instant
case class Message(  id: String,  content: String,  authorName: String,) {  val createdAt: String = Instant.now().toString}
object Message {  val t = deriveObjectType[Context, Message](    AddFields(      Field("createdAt", StringType, resolve = _.value.createdAt)    )  )}
Equivalent ObjectType (from the GraphQL SDL)
type Message {  id: ID!  content: String!  authorName: String!  createdAt: String!}

Root / Top Level Object#

Now, we have all the ObjectType that isn't a RootOperationType. We can start writing the top level objects primarily the Query and Mutation as the Subscription require a bit more work which will be described on the next page.

Schema.scala
import sangria.schema._import scala.math.minimport java.util.UUIDimport /*path to file*/.Contextimport /*path to file*/.Message
object Schema {  val limitArg = Argument("limit", IntType, defaultValue = 30)  val authorNameArg = Argument("authorName", StringType)
  val QueryType = ObjectType(    "Query",    fields[Context, Unit](      Field("messages", ListType(Message.t),        arguments = limitArg :: Nil,        // We will be updating this later on        resolve = c => List[Message]().reverse.take(min(c.arg(limitArg), 100))      ),      Field("messageBy", ListType(Message.t),        arguments = authorNameArg :: Nil,        // We will be updating this later on        resolve = c => List[Message]().reverse.filter(_.authorName == c.arg(authorNameArg))      )    )  )
  val (byArg, msgArg) = (    Argument("by", StringType),    Argument("msg", StringType)  )
  val MutationType = ObjectType(    "Mutation",    fields[Context, Unit](      Field("send", ListType(Message.t),        arguments = msgArg :: byArg :: Nil,        // We will be updating this later on        resolve = c => Message(          id = UUID.randomUUID().toString,          content = c.arg(msgArg),          authorName = c.arg(byArg)        )      )    )  )
  val t = Schema(QueryType, Some(MutationType))}
Equivalent ObjectType (from the GraphQL SDL)
type Query {  messages(limit: Int! = 30): [Message!]!  messageBy(authorName: String!): [Message!]!}
type Mutation {  send(msg: String!, by: String!): Message!}

Although the resolvers are incomplete due to lack of data, We already put in place the appropriate logic so it will be an easy refactor.