Ktor and GraphQL - Getting Started
Ktor and GraphQL - Getting Started
Learn Android & Kotlin Pricing Join Chat Search Sign In account
Hide contents
Flutter Apprentice, First Edition — Now Available!
Ktor and GraphQL:
Getting Started
Start Reading
Getting Started
What Is GraphQL?
5/5 6 Ratings
Version
GraphQL is a query language for APIs and a runtime for ful lling those queries with
your existing data. GraphQL provides a complete and understandable description of
the data in your API, giving clients the power to ask for exactly what they need and
nothing more.
Getting Started
Download the starter project by clicking the Download Materials button at the top
or bottom of the tutorial.
You’ll need IntelliJ IDEA with the Ktor plugin installed. Then, open the starter
project and wait until the IDE nishes loading the project dependencies and
indexing the project. Now, you have a fully functional GraphQL server.
Start your server by pressing the green play icon beside the main function. Test to
make sure your server is running by going to localhost:8080/graphql . You should see
the following page in your browser.
With your server up and running, next you’ll dive into what exactly is GraphQL.
What Is GraphQL?
GraphQL is a query language for your API and a server-side runtime for handling
queries. Think of GraphQL as a facade around your existing API or database.
GraphQL also leverages the use of a type system to de ne your backing data.
GraphQL isn’t tied to any speci c database or storage engine. Instead, it is backed by
your existing code and data.
API developers use GraphQL to create a schema to describe all the possible data
that clients can query through that service. A GraphQL schema consists of object
types, which de ne the kinds of objects you can request and what elds they have.
As queries come in, GraphQL validates the queries against the schema. GraphQL
then executes the validated queries. The API developer attaches each eld in a
schema to a function called a resolver. During execution, the resolver is called to
produce the value. You’ll create a resolver later in this tutorial.
But they have similarities as well. Both provide information to front-end clients in
JSON and have ways to identify if an operation is going to read or write data. Both
also end up calling functions on the server to perform different kinds of requests.
The following diagram from the ApolloGraphQL blog summarizes the difference.
Where REST tends to have multiple endpoints, GraphQL has a single endpoint.
What Is Ktor?
Ktor is an asynchronous framework for quickly creating web applications in Kotlin
with minimal effort. You can develop microservices, web applications and more.
Ktor describes itself as fun, free and open source.
Some of the more remarkable reasons to develop with Ktor include that it is:
Lightweight: Use what you need. Ktor allows you to transparently con gure only
the functionality your project requires.
Extensible: Extend what you need. With a con gurable pipeline, you can create
the extensions you need and place them anywhere you want.
Multiplatform: Run it where you need it. Built from the ground up with Kotlin
Multiplatform technology, you can deploy Ktor applications anywhere.
Asynchronous: Scale as you need it. Using Kotlin coroutines, Ktor is truly
asynchronous and highly scalable.
For this tutorial, you’ll work with Ktor as your server-side framework to build this
project.
// 1 COPY
enum class Position {
GK, // Goalkeeper
DEF, // Defender
MID, // Midfielder
FRW // Forward
}
// 2
data class Player(var uid: String, var name: String, var team: String, var position:
Position)
// 3
data class PlayerInput(val name: String, val team: String, val position: Position)
1. The Position enum class describes the different positions for a player.
2. The Player data class provides the attributes for the model.
3. The PlayerInput is the model that you’re going to send when you want to operate
with the data source.
Notice that you’re creating a mutable list of Players. This is so you can make
modi cations through GraphQL calls in a later section.
With the data created, you’ll turn your focus on wrapping an interface around the
data to facilitate reading/writing to/from the list. To do this, you’ll make use of the
Repository pattern.
interface IPlayerRepository {
fun createPlayer(player: Player)
fun deletePlayer(uid: String)
fun listPlayers() : List<Player>
fun filterPlayersByPosition(position: Position): List<Player>
fun filterPlayersByTeam(team: String): List<Player>
fun updatePlayer(uid: String, playerInput: PlayerInput)
}
This interface de nes the functionality of the player repository. This interface can
be reused to abstract calls to a database, or another REST API. In this project, you’ll
de ne the implementation for each method. Add the following below the interface:
For now, you’re working with built-in data from the list of players. So the operations
you’re going to implement are going to be from this local list. You now have all the
classes needed to expose your data with GraphQL. Well done!
Creating a Schema
Your GraphQL server uses a schema to describe the shape of your data graph. This
schema de nes a hierarchy of types with elds that populate from your back-end
data stores. The schema also speci es exactly which queries and mutations are
available for clients to execute against your data graph. Start by creating the
SchemaGraphQL.kt le in the src directory and add:
fun SchemaBuilder.schemaValue() {
// 1
val repository: IPlayerRepository = PlayerRepository()
// 2
inputType<PlayerInput>{
description = "The input of the player without the identifier"
}
// 3
type<Player>{
description = "Player object with the attributes name, team, position and
identifier"
}
// 4
enum<Position>()
}
1. De ne the repository for players that you implemented in the previous section.
2. The inputType works as a object type for input data models on the GraphQL
schema.
3. Registers the Kotlin data classes with the type method to include it in the
created schema type system.
4. Registers the Kotlin enum with the enum method to include it in the created
schema type system.
If you restart your server in IntelliJ, and refresh your browser, you should notice a
Schema tab to the far right. If you click on it, you should see your models described
in the panel shown. You can see it in the screenshot below:
You’ll notice that any description you ll when describing your model is also shown
here. This can be useful for developers who might use your interface to better
understand the models provided by your endpoint.
With the data types de ned in the schema, the next step will be to add your rst
query.
You’ll start by adding a method to query all players by a given position. Add the
following inside the SchemaBuilder.schemaValue() function:
// 1 COPY
query("playersByPosition") {
// 2
description = "Retrieve all the players by his position"
// 3
resolver { position: Position ->
try {
// 4
repository.filterPlayersByPosition(position)
} catch (e: Exception) {
emptyList<Player>()
}
}
}
1. De ne a query with a unique name and add a description for the resolver.
2. Give the method a useful description so developers better understand its usage.
3. Use a resolver accepting a position and returning a list of Player s. Notice that
you’ll call the filterPlayersByPosition you added to the IPlayerRepository
interface.
In GraphQL every property needs a resolver. The resolver is the piece of system
logic, required to resolve the response graph. Since you de ned Position enum
type, you’re able to accept it as part of the resolver. The nal step is to setup the
schema when the application is launched.
Now, run the application and, on the webpage, tap the Schema tab. You’ll see the
following result:
To test the implementation, try to run the playerByPosition query. In the Query
section, add:
Click the Query variables tab and put the following code that represents the object
in the argument eld. Here, you’re choosing to search for players who are
mid elders.
{ COPY
"position": "MID"
}
Click the middle Play button. When you execute this, you should see the following
result from the playground:
To esh out the API, add the following players and playersByTeam queries to retrieve
a list of all players, and players by team respectively.
query("players") { COPY
description = "Retrieve all players"
resolver { ->
try {
repository.listPlayers()
} catch (e: Exception) {
emptyList<Player>()
}
}
}
query("playersByTeam") {
description = "Retrieve all the players by his team"
resolver { team: String ->
try {
repository.filterPlayersByTeam(team)
} catch (e: Exception) {
emptyList<Player>()
}
}
}
Notice how the the players doesn’t require any arguments, where as playersByTeam
expects a team name as a string.
With queries complete, you can now add the ability to modify or mutate objects
using GraphQL. You’ll do that in the next section.
You’ll rst add a mutation to allow creating new players. Add a createPlayer
mutation to the SchemaBuilder.schemaValue() function:
// 1 COPY
mutation("createPlayer") {
// 2
description = "Create a new player"
// 3
resolver { playerInput: PlayerInput ->
try {
// 4
val uid = java.util.UUID.randomUUID().toString()
val player = Player(uid, playerInput.name, playerInput.team,
playerInput.position)
repository.createPlayer(player)
true
} catch (e: Exception) {
false
}
}
}
2. Give the method a description to help developers better understand the method.
3. Use a resolver accepting a PlayerInput . Recall that you de ned this class earlier
with the schema, so it can be used a typed input.
4. Create the Player object, and store it in the list.
As with queries, you’ll call the respective repository methods for each resolver that
you create. In this case, that means actions that’ll affect the result of the data. After
implementing the code above and re-running the project again, you’ll see this:
Inside the Query variables, put the following code that represents the object in the
argument eld:
{ COPY
"playerInput": {
"name": "Test player",
"position": "DEF",
"team": "Barcelona"
}
}
When you execute this, expect the following result from the playground:
You’ve just learned how to create a GraphQL application using Ktor and KGraphQL!
Although you’ve scratched the surface, there are many areas of either Ktor, or
KGraphQL you might want to explore.
We hope you enjoyed this tutorial. If you have any questions, please join the
discussion below.
raywenderlich.com Weekly
Get a weekly digest of our tutorials and courses, and receive a free in-depth email course as a
bonus!
Learn more
Started
Learn how to create a Gradle plugin within your existing Android app, or as
a standalone project that you can publish and use in any Android project.
Jun 7 2021 · Article (25 mins)
SOLID is a group of principles that lead you to write clear and organized
code without additional effort. Learn how to apply it to your SwiftUI iOS
apps.
Contributors
Comments
Show Comments.
Learn more
Places Company Community All videos. All books. One low price.
iOS & Swift About Join RW Chat A raywenderlich.com subscription is the best way to
The largest and most up-to-date learn and master mobile development — plans start at
collection of courses and books on Android & Kotlin Terms & Conditions Mobile App just $19.99/month!
iOS, Swift, Android, Kotlin, Flutter,
Flutter Privacy Policy Podcast Learn iOS, Swift, Android, Kotlin, Flutter and Dart
Dart, Server-Side Swift, Unity and
more! development and unlock our massive catalogue of 50+
Server-Side Swift Forums
books and 4,000+ videos.
Support
Unity Newsletter
Learn more
Library Help Free Books for Meetups
FAQ
Contact Us
© 2021 Razeware LLC Made with ♥ from around the world 6000+ Tutorials and counting