├── swapi.gif ├── LICENSE ├── examples.fsx ├── README.md └── swapi.fs /swapi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evelinag/fsharp-swapi/HEAD/swapi.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Evelina Gabasova 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples.fsx: -------------------------------------------------------------------------------- 1 | 2 | #r "packages/FSharp.Data/lib/net40/FSharp.Data.dll" 3 | #load "swapi.fs" 4 | open StarWars.API 5 | 6 | // Download information about all people in the Star Wars universe 7 | let people = getAllPeople() 8 | printfn "Number of people: %d" people.Length 9 | 10 | // What is the most common eye color among Star Wars characters? 11 | let eyeColor = 12 | people 13 | |> Array.groupBy (fun person -> person.EyeColor ) 14 | |> Array.map (fun (color, creatures) -> color, creatures |> Array.map (fun p -> p.Name)) 15 | |> Array.sortByDescending (fun (_, xs) -> xs.Length) 16 | 17 | // What is the average height of Star Wars characters? 18 | let height = 19 | people 20 | |> Array.choose (fun person -> person.Height.Number) 21 | |> Array.averageBy float 22 | 23 | // Download infromation about all species 24 | let species = getAllSpecies() 25 | 26 | // which species has most characters? 27 | let mostCommonSpecies = 28 | species 29 | |> Array.map (fun s -> s.Name, s.People.Length) 30 | |> Array.maxBy snd 31 | printfn "The most common species is %s with %d characters" 32 | (fst mostCommonSpecies) (snd mostCommonSpecies) 33 | 34 | // ********************************* 35 | 36 | // Get information about a specific person 37 | let p = getPerson 1 38 | printfn "%s" p.Name 39 | 40 | // which films does the person appear in? 41 | p.Films 42 | |> Array.map (fun f -> Film.Load(f).Title) 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # F# Swapi 2 | 3 | F# wrapper for [swapi.co](https://swapi.co/). 4 | 5 | ## Installation 6 | 7 | To use `fsharp-swapi`, you'll need to get the [F# Data library](http://fsharp.github.io/FSharp.Data/). 8 | 9 | To use `fsharp-swapi`, simply reference the `swapi.fs` file from your solution. You can also add the file using the paket dependency manager by adding the following line into your paket.dependencies file: 10 | 11 | github evelinag/fsharp-swapi swapi.fs 12 | 13 | See paket documentation for more details on referencing Github dependencies. 14 | See [paket documentation](https://fsprojects.github.io/Paket/github-dependencies.html) for more details on referencing Github dependencies. 15 | 16 | ## Using F# Swapi 17 | 18 | To use the library, reference `FSharp.Data` and `fsharp-swapi` from your F# code. 19 | 20 | #r "packages/FSharp.Data/lib/net40/FSharp.Data.dll" 21 | #load "swapi.fs" 22 | open StarWars.API 23 | 24 | File `examples.fsx` contains "practical" examples of usage. Head there if you're interested in the average height of a Star Wars character, or if you want to know which eye colour is the most common. 25 | 26 | ### Accessing individual resources 27 | 28 | In [swapi.co](https://swapi.co/), each resource is available through its ID number. To access each resource based on the ID, call the following functions: 29 | 30 | * `getPerson id` returns information on a given person. 31 | * `getPlanet id` returns information about a planet. 32 | * `getFilm id` returns information about a film. 33 | * `getSpecies id` gives information about a species. 34 | * `getVehicle id` gives information about a vehicle. 35 | * `getStarship id` returns information about a specific starship. 36 | 37 | All the functions use the [F# JSON type providers](http://fsharp.github.io/FSharp.Data/library/JsonProvider.html). You can access all the information they return using the dot: 38 | 39 | ![swapi.gif](swapi.gif) 40 | 41 | ### Downloading all information 42 | 43 | To download all items available for each resource in [swapi.co](https://swapi.co/), you can run the following functions: 44 | 45 | * `getAllPeople()` 46 | * `getAllPlanets()` 47 | * `getAllFilms()` 48 | * `getAllSpecies()` 49 | * `getAllVehicles()` 50 | * `getAllStarships()` 51 | 52 | The library is heavily based on [F# JSON type providers](http://fsharp.github.io/FSharp.Data/library/JsonProvider.html). 53 | 54 | -------------------------------------------------------------------------------- /swapi.fs: -------------------------------------------------------------------------------- 1 | module StarWars.API 2 | open FSharp.Data 3 | 4 | // Star Wars resource urls 5 | let [] baseUrl = "http://swapi.co/api/" 6 | let [] peopleUrl = baseUrl + "people/" 7 | let [] planetUrl = baseUrl + "planets/" 8 | let [] filmUrl = baseUrl + "films/" 9 | let [] speciesUrl = baseUrl + "species/" 10 | let [] vehicleUrl = baseUrl + "vehicles/" 11 | let [] starshipUrl = baseUrl + "starships/" 12 | 13 | // Json type providers for individual types of resources 14 | type Person = JsonProvider<"http://swapi.co/api/people/29/"> 15 | type Planet = JsonProvider<"http://swapi.co/api/planets/1/"> 16 | type Film = JsonProvider<"http://swapi.co/api/films/1/"> 17 | type Species = JsonProvider<"http://swapi.co/api/species/1/"> 18 | type Vehicle = JsonProvider<"http://swapi.co/api/vehicles/4/"> 19 | type Starship = JsonProvider<"http://swapi.co/api/starships/9/"> 20 | 21 | // Json type providers for downloading all items 22 | // from each resource 23 | type AllPeople = JsonProvider<"http://swapi.co/api/people/?page=3"> 24 | type AllPlanets = JsonProvider 25 | type AllFilms = JsonProvider 26 | type AllSpecies = JsonProvider 27 | type AllVehicles = JsonProvider 28 | type AllStarships = JsonProvider 29 | 30 | // Helper functions to get specific item using its id 31 | let getPerson id = Person.Load(peopleUrl + string id + "/") 32 | let getPlanet id = Planet.Load(planetUrl + string id + "/") 33 | let getFilm id = Film.Load(filmUrl + string id + "/") 34 | let getSpecies id = Species.Load(speciesUrl + string id + "/") 35 | let getVehicle id = Vehicle.Load(vehicleUrl + string id + "/") 36 | let getStarship id = Starship.Load(starshipUrl + string id + "/") 37 | 38 | /// Downloading all items requires paging - this type provider 39 | /// gives general access to the "next" page's url in the JSON document 40 | type Paging = JsonProvider<"""{"next": "http://swapi.co/api/people/?page=2"}"""> 41 | 42 | /// Recursively download all paged resources. The parser 43 | /// is a wrapper around the individual types for each of the resources. 44 | let rec getAll parser nextUrl acc = 45 | match nextUrl with 46 | | "" -> List.rev acc |> Array.concat 47 | | url -> 48 | let text = Http.RequestString(url) 49 | let next = Paging.Parse(text).Next 50 | let contents = parser text 51 | getAll parser next (contents::acc) 52 | 53 | // Wrappers around individual type providers for each resource 54 | let peopleParser url = AllPeople.Parse(url).Results 55 | let planetParser url = AllPlanets.Parse(url).Results 56 | let filmParser url = AllFilms.Parse(url).Results 57 | let speciesParser url = AllSpecies.Parse(url).Results 58 | let vehicleParser url = AllVehicles.Parse(url).Results 59 | let starshipParser url = AllStarships.Parse(url).Results 60 | 61 | // Functions to get all items for each resource 62 | let getAllPeople () = getAll peopleParser peopleUrl [] 63 | let getAllPlanets () = getAll planetParser planetUrl [] 64 | let getAllFilms () = getAll filmParser filmUrl [] 65 | let getAllSpecies () = getAll speciesParser speciesUrl [] 66 | let getAllVehicles () = getAll vehicleParser vehicleUrl [] 67 | let getAllStarships () = getAll starshipParser starshipUrl [] 68 | 69 | 70 | --------------------------------------------------------------------------------