Juniper: Полноценная GraphQL библиотека для Rust

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Juniper — GraphQL библиотека для Rust

Juniper — это быстрая, безопасная и эргономичная библиотека на языке Rust для построения GraphQL серверов. Она позволяет разрабатывать API с строгой типизацией, автоматической генерацией документации и поддержкой асинхронных запросов. Juniper идеально подходит для проектов, где критичны производительность, надежность и выразительность типов.

В отличие от традиционных REST API, GraphQL позволяет клиенту запрашивать только необходимые данные, что снижает нагрузку на сеть и сервер. Juniper реализует полную спецификацию GraphQL (включая подписки через WebSocket), что делает ее отличным выбором для современных веб-приложений на Rust.

Основные возможности

  • Полная поддержка GraphQL — запросы, мутации, подписки.
  • Асинхронность — из коробки работает с async/await (через futures).
  • Интеграция с популярными фреймворками — Actix-web, Rocket, Warp, Tide, Axum.
  • Автоматическая генерация схемы — на основе структур Rust.
  • Поддержка контекста — передача состояния (БД, аутентификация) в резолверы.
  • Расширяемость — кастомные скаляры, директивы, интерфейсы.
  • Безопасность — строгая типизация на уровне компиляции, предотвращает ошибки времени выполнения.
  • Документация — автоматическая генерация GraphQL Schema (SDL).

Установка

Добавьте juniper в Cargo.toml вашего проекта:

[dependencies]
juniper = "0.16"

Для интеграции с веб-фреймворком добавьте соответствующий крейт. Например, для Actix-web:

[dependencies]
juniper = "0.16"
actix-web = "4"
juniper_actix = "0.3"

Создание простого GraphQL сервера

Рассмотрим пример создания API для получения списка пользователей. Сначала определим модель данных и резолверы.

1. Определение типов GraphQL

Используем макросы #[derive(GraphQLObject)] и #[derive(GraphQLInputObject)]:

use juniper::{GraphQLObject, GraphQLInputObject};

#[derive(GraphQLObject)]
#[graphql(description = "Пользователь системы")]
struct User {
    id: i32,
    name: String,
    email: String,
}

#[derive(GraphQLInputObject)]
#[graphql(description = "Новый пользователь")]
struct NewUser {
    name: String,
    email: String,
}

2. Создание контекста и корневых запросов

Контекст обычно содержит доступ к базе данных или другим сервисам:

use std::sync::Mutex;

struct Database {
    users: Mutex<Vec<User>>,
}

impl Database {
    fn new() -> Self {
        Database {
            users: Mutex::new(vec![
                User { id: 1, name: "Alice".into(), email: "alice@example.com".into() },
                User { id: 2, name: "Bob".into(), email: "bob@example.com".into() },
            ]),
        }
    }
}

// Контекст для резолверов
pub struct Context {
    pub db: Database,
}

// Реализация типажа Context для Juniper
impl juniper::Context for Context {}

3. Определение корневого запроса (Query) и мутации (Mutation)

pub struct QueryRoot;

#[juniper::graphql_object(Context = Context)]
impl QueryRoot {
    fn users(context: &Context) -> Vec<User> {
        let db = context.db.users.lock().unwrap();
        db.clone()
    }

    fn user(context: &Context, id: i32) -> Option<User> {
        let db = context.db.users.lock().unwrap();
        db.iter().find(|u| u.id == id).cloned()
    }
}

pub struct MutationRoot;

#[juniper::graphql_object(Context = Context)]
impl MutationRoot {
    fn create_user(context: &Context, new_user: NewUser) -> User {
        let mut db = context.db.users.lock().unwrap();
        let id = db.len() as i32 + 1;
        let user = User {
            id,
            name: new_user.name,
            email: new_user.email,
        };
        db.push(user.clone());
        user
    }
}

4. Создание схемы и запуск сервера (Actix-web)

use actix_web::{web, App, HttpServer, HttpResponse, middleware};
use juniper::http::graphiql::graphiql_source;
use juniper::http::GraphQLRequest;
use std::sync::Arc;

// Создаем схему
type Schema = juniper::RootNode<'static, QueryRoot, MutationRoot>                    

Рекомендаций