Using contexts

The context type is a feature in Juniper that lets field resolvers access global data, most commonly database connections or authentication information. The context is usually created from a context factory. How this is defined is specific to the framework integration you're using, so check out the documentation for either the Iron or Rocket integration.

In this chapter, we'll show you how to define a context type and use it in field resolvers. Let's say that we have a simple user database in a HashMap:


struct Database {
    users: HashMap<i32, User>,
}

struct User {
    id: i32,
    name: String,
    friend_ids: Vec<i32>,
}

We would like a friends field on User that returns a list of User objects. In order to write such a field though, the database must be queried.

To solve this, we mark the Database as a valid context type and assign it to the user object. Then, we use the special &executor argument to access the current context object:

#[macro_use] extern crate juniper;

struct Database {
    users: HashMap<i32, User>,
}

struct User {
    id: i32,
    name: String,
    friend_ids: Vec<i32>,
}

// 1. Mark the Database as a valid context type for Juniper
impl juniper::Context for Database {}

// 2. Assign Database as the context type for User
graphql_object!(User: Database |&self| {
    // 3. Use the special executor argument
    field friends(&executor) -> Vec<&User> {
        // 4. Use the executor to access the context object
        let database = executor.context();

        // 5. Use the database to lookup users
        self.friend_ids.iter()
            .map(|id| database.users.get(id).expect("Could not find user with ID"))
            .collect()
    }

    field name() -> &str { self.name.as_str() }
    field id() -> i32 { self.id }
});

You only get an immutable reference to the context, so if you want to affect change to the execution, you'll need to use interior mutability using e.g. RwLock or RefCell.

results matching ""

    No results matching ""