This blog shows how to query top 50 most listened musicians of last.fm users with F#. The complete source code which sheds more light on function composition, unit testing, property-based testing and railway-oriented programming can be accessed on GitHub.
Type providers is a useful F# feature that allows strongly-type responses from REST APIs, CSV files, and HTML tables etc. and thus, is useful for REST APIs interaction, data analysis tasks, and much more.
To enable type providers in our project, we perform the following steps.
- Import FSharp.Data
- Provide snippet of API response.
- let [<Literal>] TopArtistsSample = """{
- "topartists":{
- "artist":[
- {
- "name":"Porcupine Tree",
- //skipped for the sake of breivety
- }
- ],
- "@attr":{
- "user":"Morbid_soul",
- "page":"1",
- "perPage":"2",
- "totalPages":"165",
- "total":"330"
- }
- }
- }"""
- type TopArtists = JsonProvider<TopArtistsSample>
Now, let us define some constants.
- [<Literal>]
- let userName = "<login here>"
- [<Literal>]
- let apiKey = "<api key here>"
- [<Literal>]
- let baseUrl = "http://ws.audioscrobbler.com"
- [<Literal>]
- let getTopArtistsPattern = "{0}/2.0/?method=user.gettopartists&user={1}&api_key={2}&period=12month&format=json"
- let path = String.Format(getTopArtistsPattern, baseUrl, userName, apiKey)
- TopArtists.Parse(text)
- let getTopArtists =
- let path = String.Format(getTopArtistsPattern, baseUrl, userName, apiKey)
- let data = Http.Request(path)
- match data.Body with
- | Text text -> TopArtists.Parse(text).Topartists.Artist
- | _ -> null
You may have noticed that we didn't handle any possible exceptions when performing the call. To do this, we will wrap our result type inside the monadic type which indicates whether the function executed successfully or not.
- type Result<'TSuccess,'TFailure> =
- | Success of 'TSuccess
- | Failure of 'TFailure
Now, our final function makes use of declared type, as shown below.
- let getTopArtists () =
- try
- let path = String.Format(getTopArtistsPattern, baseUrl, userName, apiKey)
- let data = Http.Request(path)
- match data.Body with
- | Text text -> Success(TopArtists.Parse(text).Topartists.Artist)
- | _ -> Failure "getTopArtists. Unexpected format of reponse message"
- with
- | ex -> Failure ex.Message

Join the conversation! Your thoughts help the community grow.