This took most of today to get working.
GraphQL interface to a list of names.. to can query by id, and can add names. There's no dupe check, no remove/delete, not even a way to enumerate stored values. The trickiest part of the incrementing id for addPerson. Initially I reused some of the HashMap in a Mutex pattern to store u32s, well u8 at first but that doesn't cast to a juniper scalar type. I don't know why that didn't work. The incremented value didn't seem to persist in the hash.
This commit is contained in:
commit
b7211a77e4
|
@ -0,0 +1 @@
|
|||
/target
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "rust-graphql-example"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
juniper_rocket = "0.8.0"
|
||||
juniper = "0.15.7"
|
||||
rocket = "0.5.0-rc.1"
|
|
@ -0,0 +1,155 @@
|
|||
extern crate rocket;
|
||||
|
||||
use std::sync::{ atomic::AtomicUsize, atomic::Ordering, Mutex };
|
||||
use std::{ collections::HashMap };
|
||||
use juniper::{ EmptySubscription, RootNode, graphql_object, Context };
|
||||
use rocket::{ response::content, Rocket, State };
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Person {
|
||||
id: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl Person {
|
||||
pub fn new(id: String, name: String) -> Person {
|
||||
Person { id, name }
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<&str> {
|
||||
Some(self.name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[graphql_object(context = Database)]
|
||||
impl Person {
|
||||
fn id(&self) -> &str {
|
||||
&self.id
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<&str> {
|
||||
Some(self.name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Database {
|
||||
people: Mutex<HashMap<String, Person>>,
|
||||
next_id: AtomicUsize,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new() -> Database {
|
||||
let database = Database {
|
||||
people: Mutex::new(HashMap::new()),
|
||||
next_id: AtomicUsize::new(1),
|
||||
};
|
||||
database
|
||||
}
|
||||
|
||||
pub fn get_person(&self, id: &str) -> Option<Person> {
|
||||
let people = self.people.lock().expect("Couldn't lock people");
|
||||
match people.get(id) {
|
||||
Some(person) => Some(person.to_owned()),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_person(&self, person: Person) {
|
||||
self.people.lock().expect("Couldn't lock people").insert(person.id.to_owned(), person);
|
||||
}
|
||||
|
||||
pub fn new_id(&self) -> usize {
|
||||
self.next_id.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn new_person(&self, name: String) -> Option<Person> {
|
||||
let person = Person {
|
||||
id: self.new_id().to_string(),
|
||||
name,
|
||||
};
|
||||
self.people.lock().expect("lock people hashmap").insert(person.id.to_owned(), person.to_owned());
|
||||
Some(person)
|
||||
}
|
||||
}
|
||||
|
||||
impl Context for Database {}
|
||||
|
||||
pub struct Query;
|
||||
#[graphql_object(context = Database)]
|
||||
impl Query {
|
||||
#[graphql(arguments(id(description = "id of the human")))]
|
||||
fn human(database: &Database, id: String) -> Option<Person> {
|
||||
database.get_person(&id)
|
||||
}
|
||||
}
|
||||
|
||||
struct Mutations;
|
||||
|
||||
#[graphql_object(context = Database)]
|
||||
impl Mutations {
|
||||
fn addHuman(database: &Database, id: String, name: String) -> Person {
|
||||
let new_guy = Person::new(id, name);
|
||||
database.add_person(new_guy.to_owned());
|
||||
new_guy.to_owned()
|
||||
}
|
||||
|
||||
fn newId(database: &Database) -> i32 {
|
||||
database.new_id() as i32
|
||||
}
|
||||
|
||||
fn newPerson(database: &Database, name: String) -> Option<Person> {
|
||||
database.new_person(name)
|
||||
}
|
||||
}
|
||||
|
||||
type Schema = RootNode<'static, Query, Mutations, EmptySubscription<Database>>;
|
||||
|
||||
#[rocket::get("/")]
|
||||
fn graphiql() -> content::Html<String> {
|
||||
juniper_rocket::graphiql_source("/graphql", None)
|
||||
}
|
||||
|
||||
#[rocket::get("/graphql?<request>")]
|
||||
fn get_graphql_handler(
|
||||
context: &State<Database>,
|
||||
request: juniper_rocket::GraphQLRequest,
|
||||
schema: &State<Schema>,
|
||||
) -> juniper_rocket::GraphQLResponse {
|
||||
request.execute_sync(&*schema, &*context)
|
||||
}
|
||||
|
||||
#[rocket::post("/graphql", data = "<request>")]
|
||||
fn post_graphql_handler(
|
||||
context: &State<Database>,
|
||||
request: juniper_rocket::GraphQLRequest,
|
||||
schema: &State<Schema>,
|
||||
) -> juniper_rocket::GraphQLResponse {
|
||||
request.execute_sync(&*schema, &*context)
|
||||
}
|
||||
|
||||
#[rocket::get("/rest/<id>")]
|
||||
fn get_rest(id: String, context: &State<Database>) -> Option<String> {
|
||||
match context.get_person(&id) {
|
||||
None => None,
|
||||
Some(person) => Some(person.name().unwrap().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[rocket::main]
|
||||
async fn main() {
|
||||
Rocket::build()
|
||||
.manage(Database::new())
|
||||
.manage(Schema::new(
|
||||
Query,
|
||||
Mutations,
|
||||
EmptySubscription::<Database>::new(),
|
||||
))
|
||||
.mount(
|
||||
"/",
|
||||
rocket::routes![graphiql, get_graphql_handler, post_graphql_handler, get_rest],
|
||||
)
|
||||
.launch()
|
||||
.await
|
||||
.expect("server to launch");
|
||||
}
|
Loading…
Reference in New Issue