I'm trying to deserialize a Spotify metadata JSON from the web API (specifications). I'm using hyper to retrieve the JSON from the server and serde to turn the JSON into something I can actually use within Rust. The JSON is retrieved from the server just fine, but when I try to turn the JSON into an object that can be used Rust panicks and throws an error:
thread '<main>' panicked at 'called 'Result::unwrap()' on an 'Err' value: SyntaxError("expected value", 11, 21)', ../src/libcore/result.rs:746
This is not helpful in the least way, because it doesn't indicate where things go wrong at all. When searching the web I stumbled upon a serde issue, which leads me to think that the problem is related to the nested structure of the JSON.
Can anyone see where things go wrong? Fixing the error would be the best solution for me, but if another crate turns out to be a better solution I'd like to hear that too. I've already tried rustc-serialize, but that crate can't handle the 'type' variables within the json.
The code I use is:
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
#![feature(custom_attribute)]
extern crate hyper;
extern crate serde;
extern crate serde_json;
use std::io::Read;
use hyper::Client;
use hyper::header::Connection;
#[derive(Serialize, Deserialize)]
struct Track_Full {
album: Album_Simp,
artists: Vec<Artist_Simp>,
available_markets: Vec<String>,
disc_number: u8,
duration_ms: u32,
explicit: bool,
external_ids: External_IDs,
external_urls: External_URLs,
href: String,
id: String,
name: String,
popularity: u8,
preview_url: String,
track_number: u8,
#[serde(rename="type")]
_type: String,
uri: String
}
#[derive(Serialize, Deserialize)]
struct Album_Simp {
album_type: String,
available_markets: Vec<String>,
external_urls: External_URLs,
href: String,
id: String,
images: Vec<Image>,
name: String,
#[serde(rename="type")]
_type: String,
uri: String
}
#[derive(Serialize, Deserialize)]
struct Artist_Simp {
external_urls: External_URLs,
href: String,
id: String,
name: String,
#[serde(rename="type")]
_type: String,
uri: String
}
#[derive(Serialize, Deserialize)]
struct External_IDs {
isrc: String
}
#[derive(Serialize, Deserialize)]
struct External_URLs {
spotify: String
}
#[derive(Serialize, Deserialize)]
struct Image {
height: u8,
url: String,
width: u8
}
fn main() {
// Create a client.
let mut client = Client::new();
// Creating an outgoing request.
let mut res = client.get("https://api.spotify.com/v1/tracks/0eGsygTp906u18L0Oimnem")
// set a header
.header(Connection::close())
// let 'er go!
.send().unwrap();
// Read the Response.
let mut body = String::new();
res.read_to_string(&mut body).unwrap();
println!("{}", body);
let deserialized: Track_Full = serde_json::from_str(&body).unwrap();
}
The JSON:
{
"album" : {
"album_type" : "album",
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ],
"external_urls" : {
"spotify" : "https://open.spotify.com/album/6TJmQnO44YE5BtTxH8pop1"
},
"href" : "https://api.spotify.com/v1/albums/6TJmQnO44YE5BtTxH8pop1",
"id" : "6TJmQnO44YE5BtTxH8pop1",
"images" : [ {
"height" : 640,
"url" : "https://i.scdn.co/image/8e13218039f81b000553e25522a7f0d7a0600f2e",
"width" : 629
}, {
"height" : 300,
"url" : "https://i.scdn.co/image/8c1e066b5d1045038437d92815d49987f519e44f",
"width" : 295
}, {
"height" : 64,
"url" : "https://i.scdn.co/image/d49268a8fc0768084f4750cf1647709e89a27172",
"width" : 63
} ],
"name" : "Hot Fuss",
"type" : "album",
"uri" : "spotify:album:6TJmQnO44YE5BtTxH8pop1"
},
"artists" : [ {
"external_urls" : {
"spotify" : "https://open.spotify.com/artist/0C0XlULifJtAgn6ZNCW2eu"
},
"href" : "https://api.spotify.com/v1/artists/0C0XlULifJtAgn6ZNCW2eu",
"id" : "0C0XlULifJtAgn6ZNCW2eu",
"name" : "The Killers",
"type" : "artist",
"uri" : "spotify:artist:0C0XlULifJtAgn6ZNCW2eu"
} ],
"available_markets" : [ "AD", "AR", "AT", "AU", "BE", "BG", "BO", "BR", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "EC", "EE", "ES", "FI", "FR", "GR", "GT", "HK", "HN", "HU", "IE", "IS", "IT", "LI", "LT", "LU", "LV", "MC", "MT", "MY", "NI", "NL", "NO", "NZ", "PA", "PE", "PH", "PL", "PT", "PY", "RO", "SE", "SG", "SI", "SK", "SV", "TR", "TW", "UY" ],
"disc_number" : 1,
"duration_ms" : 222075,
"explicit" : false,
"external_ids" : {
"isrc" : "USIR20400274"
},
"external_urls" : {
"spotify" : "https://open.spotify.com/track/0eGsygTp906u18L0Oimnem"
},
"href" : "https://api.spotify.com/v1/tracks/0eGsygTp906u18L0Oimnem",
"id" : "0eGsygTp906u18L0Oimnem",
"name" : "Mr. Brightside",
"popularity" : 74,
"preview_url" : "https://p.scdn.co/mp3-preview/934da7155ec15deb326635d69d050543ecbee2b4",
"track_number" : 2,
"type" : "track",
"uri" : "spotify:track:0eGsygTp906u18L0Oimnem"
}
You've attempted to parse some JSON and it failed. When you called unwrap
on the Result
, the program panicked because of this failure:
SyntaxError("expected value", 11, 21)
The documentation for SyntaxError
says the numbers are the line and column of the error. Line 11, column 21 is:
"height" : 640,
^
Looking at your structure, you have declared the height to be a u8
, an 8-bit unsigned number. This has the allowed values of 0-255. 640 does not fit into that. Increasing the value to a u32
allows the JSON to be parsed.
Additionally, Rust style is to use CamelCase
identifiers without consecutive capital letters for structs. External_URLs
-> ExternalUrls
. The compiler will actually warn you about this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With