abgespaced

An API that combines The DB Bahnhof API and the Space API
git clone git://archive.git.mtrnord.blog/MTRNord/abgespaced.git
Log | Files | Refs

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 }