api_provider.rs (5569B)
1 use juniper::{EmptyMutation, Value}; 2 use rocket::response::content; 3 use rocket::State; 4 5 #[derive(juniper::GraphQLObject)] 6 struct TrainMovement { 7 movement_type: String, 8 train_number: String, 9 platform: String, 10 time: String, 11 stops: Vec<String>, 12 } 13 14 #[derive(juniper::GraphQLObject)] 15 struct Timetables { 16 next_arrivals: Vec<TrainMovement>, 17 next_depatures: Vec<TrainMovement>, 18 } 19 20 #[derive(juniper::GraphQLObject)] 21 struct Location { 22 latitude: f64, 23 longitude: f64, 24 } 25 26 #[derive(juniper::GraphQLObject)] 27 #[graphql(description = "A Station in the Bahn Universe")] 28 struct Station { 29 name: String, 30 primary_eva_id: Option<i32>, 31 has_local_public_transport: bool, 32 has_taxi_rank: bool, 33 has_stepless_access: bool, 34 has_wifi: bool, 35 location: Option<Location>, 36 timetables: Timetables, 37 } 38 39 #[derive(juniper::GraphQLObject)] 40 #[graphql(description = "A Space in the Space API")] 41 struct Space { 42 #[graphql(description = "The human readable name of a *Space")] 43 name: String, 44 #[graphql(description = "All Bahn Stations in a radius of 2000m")] 45 stations: Vec<Station>, 46 } 47 48 struct Query; 49 50 enum NotFoundErr { 51 NotFound, 52 } 53 54 impl juniper::IntoFieldError for NotFoundErr { 55 fn into_field_error(self) -> juniper::FieldError { 56 match self { 57 NotFoundErr::NotFound => { 58 juniper::FieldError::new("The searched space does not exist", Value::null()) 59 } 60 } 61 } 62 } 63 64 #[juniper::object] 65 impl Query { 66 fn apiVersion() -> &str { 67 "0.1.0" 68 } 69 70 fn space(name: String) -> Result<Space, NotFoundErr> { 71 let searched_space_coordinates = crate::spaceapi::find_space(&name); 72 match searched_space_coordinates { 73 Ok(searched_space_coordinates_unpacked) => { 74 let stations = crate::bahnapi::nearby( 75 searched_space_coordinates_unpacked["lat"], 76 searched_space_coordinates_unpacked["lon"], 77 Some(2000), 78 Some(20), 79 ); 80 let mut stations_usable = Vec::new(); 81 82 if let Ok(x) = stations { 83 let data = x.data.unwrap(); 84 let nearby_stations = data.nearby.stations; 85 for station in nearby_stations.into_iter() { 86 let primary_eva_id: Option<i32>; 87 if station.primary_eva_id.is_some() { 88 let primary_eva_id_raw: i32 = station.primary_eva_id.unwrap() as i32; 89 primary_eva_id = Some(primary_eva_id_raw); 90 } else { 91 primary_eva_id = None; 92 } 93 let has_stepless_access: bool; 94 if station.has_stepless_access == "yes" { 95 has_stepless_access = true 96 } else { 97 has_stepless_access = false 98 } 99 let location: Option<Location>; 100 if station.location.is_some() { 101 let location_bahn = station.location.unwrap(); 102 location = Some(Location { 103 latitude: location_bahn.latitude, 104 longitude: location_bahn.longitude, 105 }); 106 } else { 107 location = None; 108 } 109 let station_usable = Station { 110 name: station.name, 111 primary_eva_id, 112 has_local_public_transport: station.has_local_public_transport, 113 has_taxi_rank: station.has_taxi_rank, 114 has_stepless_access, 115 has_wifi: station.has_wi_fi, 116 location, 117 timetables: Timetables { 118 next_arrivals: vec![], 119 next_depatures: vec![], 120 }, 121 }; 122 stations_usable.push(station_usable); 123 } 124 } 125 let space = Space { 126 name, 127 stations: stations_usable, 128 }; 129 return Ok(space); 130 } 131 Err(e) => { 132 error!("{:?}", e); 133 } 134 } 135 Err(NotFoundErr::NotFound) 136 } 137 } 138 139 // A root schema consists of a query and a mutation. 140 // Request queries can be executed against a RootNode. 141 type Schema = juniper::RootNode<'static, Query, EmptyMutation<()>>; 142 143 #[rocket::get("/")] 144 fn graphiql() -> content::Html<String> { 145 juniper_rocket::graphiql_source("/graphql") 146 } 147 148 #[rocket::get("/graphql?<request>")] 149 fn get_graphql_handler( 150 request: juniper_rocket::GraphQLRequest, 151 schema: State<Schema>, 152 ) -> juniper_rocket::GraphQLResponse { 153 request.execute(&schema, &()) 154 } 155 156 #[rocket::post("/graphql", data = "<request>")] 157 fn post_graphql_handler( 158 request: juniper_rocket::GraphQLRequest, 159 schema: State<Schema>, 160 ) -> juniper_rocket::GraphQLResponse { 161 request.execute(&schema, &()) 162 } 163 164 pub fn start_api() { 165 rocket::ignite() 166 .manage(Schema::new(Query, EmptyMutation::<()>::new())) 167 .mount( 168 "/", 169 rocket::routes![graphiql, get_graphql_handler, post_graphql_handler], 170 ) 171 .launch(); 172 }