GraphQL API mit Rust: Schritt-für-Schritt-Tutorial
GraphQL ist eine Abfragesprache für APIs, die es Clients ermöglicht, nur die benötigten Daten zu erhalten. Rust wiederum ist bekannt für seine Leistung und Speichersicherheit. In diesem Tutorial erstellen wir eine vollwertige GraphQL-API in Rust unter Verwendung der Bibliotheken Juniper und Actix-web. Sie erfahren, wie Sie einen Server einrichten, ein Schema definieren, Abfragen und Mutationen implementieren und die API testen.
Dieses Material ist nützlich für Entwickler, die mit den Grundlagen von Rust und der Webentwicklung vertraut sind. Wir konzentrieren uns auf die praktische Umsetzung und vermeiden übermäßige Theorie.
Projekteinrichtung und Installation der Abhängigkeiten
Zunächst erstellen wir ein neues Rust-Projekt:
cargo new rust-graphql-apicd rust-graphql-apiFügen wir die erforderlichen Abhängigkeiten in der Datei Cargo.toml hinzu:
[dependencies]actix-web = "4"actix-rt = "2"serde = { version = "1", features = ["derive"] }serde_json = "1"juniper = "0.16"juniper_actix = "2"Hier ist actix-web das Web-Framework und juniper die Bibliothek für die Arbeit mit GraphQL. juniper_actix stellt die Integration zwischen beiden sicher.
Erstellung eines grundlegenden GraphQL-Schemas
Jetzt definieren wir ein einfaches Datenmodell und Schema. Als Beispiel erstellen wir ein System zur Verwaltung von Benutzern und Beiträgen.
Erstellen wir die Datei src/schema.rs:
use juniper::{GraphQLObject, GraphQLInputObject, RootNode};
#[derive(GraphQLObject)]#[graphql(description = "Systembenutzer")]pub struct User { pub id: i32, pub name: String, pub email: String,}
#[derive(GraphQLInputObject)]#[graphql(description = "Eingabedaten zum Erstellen eines Benutzers")]pub struct NewUser { pub name: String, pub email: String,}
#[derive(GraphQLObject)]#[graphql(description = "Benutzerbeitrag")]pub struct Post { pub id: i32, pub title: String, pub body: String, pub author_id: i32,}
pub struct QueryRoot;
#[juniper::object]impl QueryRoot { fn users() -> Vec<User> { vec![ User { id: 1, name: "Alexej".into(), email: "alex@example.com".into() }, User { id: 2, name: "Maria".into(), email: "maria@example.com".into() }, ] }
fn posts() -> Vec<Post> { vec![ Post { id: 1, title: "Erster Eintrag".into(), body: "Text des Beitrags".into(), author_id: 1 }, ] }}
pub struct MutationRoot;
#[juniper::object]impl MutationRoot { fn create_user(new_user: NewUser) -> User { User { id: 3, name: new_user.name, email: new_user.email, } }}
pub type Schema = RootNode<'static, QueryRoot, MutationRoot>;Wir haben zwei Root-Objekte definiert: QueryRoot für Abfragen (Datenabruf) und MutationRoot für Mutationen (Datenänderung). #[derive(GraphQLObject)] generiert automatisch GraphQL-Typen aus Rust-Strukturen.
Einrichtung des Webservers und Integration mit Actix-web
Jetzt erstellen wir die Hauptdatei src/main.rs zum Starten des Servers:
mod schema;
use actix_web::{web, App, HttpServer, HttpResponse, middleware};use juniper_actix::{graphql_handler, playground_handler};use std::sync::Arc;
use crate::schema::Schema;
async fn graphql_route( req: actix_web::HttpRequest, payload: actix_web::web::Payload, schema: web::Data<Arc<Schema>>,) -> actix_web::Result<HttpResponse> { let context = (); graphql_handler(&schema, &context, req, payload).await}
async fn playground_route() -> actix_web::Result<HttpResponse> { playground_handler("/graphql", None).await}
#[actix_web::main]async fn main() -> std::io::Result<()> { let