Prerequisites

Before we start, ensure you have the following installed:

  • Rust (latest stable version)
  • Cargo (Rust's package manager)

You can check your Rust installation by running:

rustc --version

Setting Up the Project

  1. Create a new Rust project:

Open your terminal and run:

   cargo new rust_graphql_server
   cd rust_graphql_server
  1. Add Dependencies:

Open Cargo.toml and add the following dependencies:

   [dependencies]
   async-graphql = "4.0"
   async-graphql-warp = "4.0"
   warp = "0.3"
   tokio = { version = "1", features = ["full"] }
   serde = { version = "1.0", features = ["derive"] }
   serde_json = "1.0"

These dependencies include async-graphql for GraphQL support, warp for the web server, and tokio as the async runtime.

Creating the GraphQL Schema

  1. Define the Data Model:

Create a new file src/models.rs and define a simple data model:

   use serde::{Deserialize, Serialize};

   #[derive(Debug, Serialize, Deserialize)]
   pub struct User {
       pub id: i32,
       pub name: String,
       pub email: String,
   }
  1. Define GraphQL Schema:

In the src/main.rs, import the necessary modules and define the schema:

   use async_graphql::{Schema, Object};
   use async_graphql_warp::GraphQLResponse;
   use warp::Filter;

   mod models;
   use models::User;

   struct Query;

   #[Object]
   impl Query {
       async fn user(&self, id: i32) -> Option<User> {
           Some(User {
               id,
               name: "John Doe".to_string(),
               email: "[email protected]".to_string(),
           })
       }
   }

   type AppSchema = Schema<Query, async_graphql::EmptyMutation, async_graphql::EmptySubscription>;

   fn create_schema() -> AppSchema {
       Schema::build(Query, async_graphql::EmptyMutation, async_graphql::EmptySubscription)
           .finish()
   }

Setting Up the Server

  1. Create the Warp Filter:

Still in src/main.rs, set up the warp filter to handle GraphQL requests:

   #[tokio::main]
   async fn main() {
       let schema = create_schema();

       let graphql_filter = async_graphql_warp::graphql(schema)
           .and_then(|(schema, request): (_, async_graphql::Request)| async move {
               let response = schema.execute(request).await;
               GraphQLResponse::from(response)
           });

       warp::serve(graphql_filter).run(([127, 0, 0, 1], 3030)).await;
   }
  1. Run the Server:

Now you can run your server with:

   cargo run

Your GraphQL server will be available at http://localhost:3030/graphql.

Testing the GraphQL API

You can test your GraphQL API using a tool like Postman or Insomnia, or you can use a browser extension like GraphiQL. Here’s how to query the user:

  1. Open your GraphQL client.
  2. Send a POST request to http://localhost:3030/graphql with the following query:
   {
       user(id: 1) {
           id
           name
           email
       }
   }
  1. Expected Response:

You should receive a response similar to the following:

   {
       "data": {
           "user": {
               "id": 1,
               "name": "John Doe",
               "email": "[email protected]"
           }
       }
   }

Conclusion and Best Practices

In this tutorial, we have built a simple GraphQL server in Rust using async-graphql and warp. Here are a few best practices to consider when developing with Rust and GraphQL:

  • Error Handling: Always handle potential errors gracefully. Use Rust's Result type effectively to manage errors.
  • Schema Design: Plan your GraphQL schema carefully. A well-designed schema can greatly improve the maintainability of your API.
  • Testing: Write tests for your GraphQL queries and mutations to ensure they behave as expected.

By following these practices, you can create robust and efficient GraphQL APIs in Rust.

Learn more with useful resources