Compare commits
No commits in common. "trunk" and "binary" have entirely different histories.
|
@ -1 +0,0 @@
|
||||||
/target
|
|
File diff suppressed because it is too large
Load Diff
16
Cargo.toml
16
Cargo.toml
|
@ -1,16 +0,0 @@
|
||||||
[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"
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0"
|
|
||||||
|
|
||||||
[dependencies.rocket]
|
|
||||||
version = "0.5.0-rc.1"
|
|
||||||
features = ["json"]
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Playing around with Rust, Rocket, Juniper
|
|
||||||
|
|
||||||
Little demo/test playing with Rust, Rocket, Juniper to get a GraphQL interface to a list of names basicly.
|
|
||||||
|
|
||||||
My Rust knowlage is rusty.. took me most of a day to get something together to compile a schema. Threadsafey was killing me on that incrementing id for about two hours. By the end when wrapping that `.values()` iter in a Juniper `graphql_object` I actually wrote that and it compiled first time! Very Wow.
|
|
||||||
|
|
||||||
![Screenshot of me using the Graphiql interface hosted by the app](https://xeen.dev/alex/rust-graphql-goof/raw/branch/binary/demo.png)
|
|
|
@ -1,42 +0,0 @@
|
||||||
use rocket::fairing::AdHoc;
|
|
||||||
use rocket::{ response::content, State };
|
|
||||||
use juniper::{ EmptySubscription };
|
|
||||||
|
|
||||||
use crate::model::Database;
|
|
||||||
use crate::schema::{ Schema, Query, Mutations };
|
|
||||||
|
|
||||||
#[rocket::get("/graphiql")]
|
|
||||||
fn graphiql() -> content::Html<String> {
|
|
||||||
juniper_rocket::graphiql_source("/graphql/", None)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::get("/?<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("/", data = "<request>")]
|
|
||||||
fn post_graphql_handler(
|
|
||||||
context: &State<Database>,
|
|
||||||
request: juniper_rocket::GraphQLRequest,
|
|
||||||
schema: &State<Schema>,
|
|
||||||
) -> juniper_rocket::GraphQLResponse {
|
|
||||||
request.execute_sync(&*schema, &*context)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stage() -> AdHoc {
|
|
||||||
let schema = Schema::new(
|
|
||||||
Query,
|
|
||||||
Mutations,
|
|
||||||
EmptySubscription::<Database>::new(),
|
|
||||||
);
|
|
||||||
AdHoc::on_ignite("Add graphql endpoints", |rocket| async {
|
|
||||||
rocket
|
|
||||||
.mount("/graphql", rocket::routes![graphiql, get_graphql_handler, post_graphql_handler])
|
|
||||||
.manage(schema)
|
|
||||||
})
|
|
||||||
}
|
|
18
src/main.rs
18
src/main.rs
|
@ -1,18 +0,0 @@
|
||||||
use rocket::Rocket;
|
|
||||||
use model::Database;
|
|
||||||
|
|
||||||
mod graphql;
|
|
||||||
mod model;
|
|
||||||
mod rest;
|
|
||||||
mod schema;
|
|
||||||
|
|
||||||
#[rocket::main]
|
|
||||||
async fn main() {
|
|
||||||
Rocket::build()
|
|
||||||
.attach(graphql::stage())
|
|
||||||
.attach(rest::stage())
|
|
||||||
.manage(Database::new())
|
|
||||||
.launch()
|
|
||||||
.await
|
|
||||||
.expect("server to launch");
|
|
||||||
}
|
|
68
src/model.rs
68
src/model.rs
|
@ -1,68 +0,0 @@
|
||||||
use std::sync::{ atomic::AtomicUsize, atomic::Ordering, Mutex };
|
|
||||||
use std::{ collections::HashMap };
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Person {
|
|
||||||
id: String,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Person {
|
|
||||||
pub fn new(id: String, name: String) -> Person {
|
|
||||||
Person { id, name }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> &str {
|
|
||||||
self.id.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub 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 list_people(&self) -> Vec<Person> {
|
|
||||||
self.people.lock().expect("lock people").values().map(|person| person.to_owned()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
27
src/rest.rs
27
src/rest.rs
|
@ -1,27 +0,0 @@
|
||||||
use rocket::fairing::AdHoc;
|
|
||||||
use rocket::serde::json::Json;
|
|
||||||
use rocket::State;
|
|
||||||
use crate::model::{
|
|
||||||
Database,
|
|
||||||
Person,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[rocket::get("/people", format = "json")]
|
|
||||||
fn people_list(context: &State<Database>) -> Json<Vec<Person>> {
|
|
||||||
Json(context.list_people())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rocket::get("/people/<id>", format = "json")]
|
|
||||||
fn people_detail(id: String, context: &State<Database>) -> Option<Json<Person>> {
|
|
||||||
match context.get_person(&id) {
|
|
||||||
None => None,
|
|
||||||
Some(person) => Some(Json(person))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stage() -> AdHoc {
|
|
||||||
AdHoc::on_ignite("Add REST endpoint", |rocket| async {
|
|
||||||
rocket
|
|
||||||
.mount("/rest", rocket::routes![people_detail, people_list])
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
impl Context for Database {}
|
|
||||||
|
|
||||||
use juniper::{ EmptySubscription, RootNode, graphql_object, Context };
|
|
||||||
use crate::model::{ Database, Person };
|
|
||||||
|
|
||||||
#[graphql_object(context = Database)]
|
|
||||||
impl Person {
|
|
||||||
fn id(&self) -> &str {
|
|
||||||
self.id()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> Option<&str> {
|
|
||||||
self.name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Query;
|
|
||||||
#[graphql_object(context = Database)]
|
|
||||||
impl Query {
|
|
||||||
#[graphql(arguments(id(description = "id of the person")))]
|
|
||||||
fn personById(database: &Database, id: String) -> Option<Person> {
|
|
||||||
database.get_person(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn people(database: &Database) -> Vec<Person> {
|
|
||||||
database.list_people()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Schema = RootNode<'static, Query, Mutations, EmptySubscription<Database>>;
|
|
Binary file not shown.
Loading…
Reference in New Issue