I am trying to poll the GitHub API for issues and print them out. To do so, I need to deserialize a nested JSON structure that I receive from a cURL GET request.
I am trying to get the url
for all the objects in the items
array:
{
"total_count": 4905,
"incomplete_results": false,
"items": [
{
"url": "https://api.github.com/repos/servo/saltfs/issues/789",
"repository_url": "https://api.github.com/repos/servo/saltfs",
"labels_url":
"https://api.github.com/repos/servo/saltfs/issues/789/labels{/name}",
"comments_url": "https://api.github.com/repos/servo/saltfs/issues/789/comments",
"events_url": "https://api.github.com/repos/servo/saltfs/issues/789/events",
"html_url": "https://github.com/servo/saltfs/issues/789",
"id": 293260512,
"number": 789,
"title": "Stop setting $CARGO_HOME to its default value",
"user": {
"login": "SimonSapin",
"id": 291359,
"avatar_url": "https://avatars0.githubusercontent.com/u/291359?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/SimonSapin",
"html_url": "https://github.com/SimonSapin",
"followers_url": "https://api.github.com/users/SimonSapin/followers",
"following_url": "https://api.github.com/users/SimonSapin/following{/other_user}",
"gists_url": "https://api.github.com/users/SimonSapin/gists{/gist_id}",
"starred_url": "https://api.github.com/users/SimonSapin/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/SimonSapin/subscriptions",
"organizations_url": "https://api.github.com/users/SimonSapin/orgs",
"repos_url": "https://api.github.com/users/SimonSapin/repos",
"events_url": "https://api.github.com/users/SimonSapin/events{/privacy}",
"received_events_url": "https://api.github.com/users/SimonSapin/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"id": 341722396,
"url": "https://api.github.com/repos/servo/saltfs/labels/E-easy",
"name": "E-easy",
"color": "02e10c",
"default": false
}
],
"state": "open",
"locked": false,
"assignee": null,
"assignees": [
],
"milestone": null,
"comments": 0,
"created_at": "2018-01-31T18:16:09Z",
"updated_at": "2018-01-31T18:16:49Z",
"closed_at": null,
"author_association": "MEMBER",
"body": "In `buildbot/master/files/config/environments.py` we set `CARGO_HOME` to Cargo’s default value. Now that `mach` does not set it (since https://github.com/servo/servo/pull/19395), this has no effect. We can remove these lines.",
"score": 1.0
},
{
"url": "https://api.github.com/repos/servo/servo/issues/19916",
"repository_url": "https://api.github.com/repos/servo/servo",
"labels_url": "https://api.github.com/repos/servo/servo/issues/19916/labels{/name}",
"comments_url": "https://api.github.com/repos/servo/servo/issues/19916/comments",
"events_url": "https://api.github.com/repos/servo/servo/issues/19916/events",
"html_url": "https://github.com/servo/servo/issues/19916",
"id": 293237180,
"number": 19916,
"title": "Use a macro to create null-terminated C strings",
"user": {
"login": "jdm",
"id": 27658,
"avatar_url": "https://avatars1.githubusercontent.com/u/27658?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/jdm",
"html_url": "https://github.com/jdm",
"followers_url": "https://api.github.com/users/jdm/followers",
"following_url": "https://api.github.com/users/jdm/following{/other_user}",
"gists_url": "https://api.github.com/users/jdm/gists{/gist_id}",
"starred_url": "https://api.github.com/users/jdm/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/jdm/subscriptions",
"organizations_url": "https://api.github.com/users/jdm/orgs",
"repos_url": "https://api.github.com/users/jdm/repos",
"events_url": "https://api.github.com/users/jdm/events{/privacy}",
"received_events_url": "https://api.github.com/users/jdm/received_events",
"type": "User",
"site_admin": false
},
"labels": [
{
"id": 89384911,
"url": "https://api.github.com/repos/servo/servo/labels/C-assigned",
"name": "C-assigned",
"color": "02d7e1",
"default": false
},
{
"id": 15997664,
"url": "https://api.github.com/repos/servo/servo/labels/E-easy",
"name": "E-easy",
"color": "02e10c",
"default": false
},
{
"id": 135307111,
"url": "https://api.github.com/repos/servo/servo/labels/I-cleanup",
"name": "I-cleanup",
"color": "e11d21",
"default": false
}
],
"state": "open",
"locked": false,
"assignee": null,
"assignees": [
],
"milestone": null,
"comments": 3,
"created_at": "2018-01-31T17:04:06Z",
"updated_at": "2018-01-31T22:03:56Z",
"closed_at": null,
"author_association": "MEMBER",
"body": "When we write them by hand (eg. `b\"some string\\0\"`), we invariably get them wrong in ways that are tricky to notice (https://github.com/servo/servo/pull/19915). We should use a macro like this instead:\r\n```rust\r\nmacro_rules! c_str {\r\n ($str:expr) => {\r\n concat!($str, \"\\0\").as_bytes()\r\n }\r\n}\r\n```\r\nThis would allow us to write code like `(c_str!(\"PEParseDeclarationDeclExpected\"), Action::Skip)` instead of https://github.com/emilio/servo/blob/d82c54bd3033cc3277ebeb4854739bebe4e20f2f/ports/geckolib/error_reporter.rs#L237. We should be able to clean up all of the uses in that file.\r\n\r\nNo need to run any automated tests; if it builds with `./mach build-geckolib`, then it's good enough for a pull request.",
"score": 1.0
}
]}
My request
function makes a cURL request and receives the above JSON. I then use serde_json to deserialize the JSON
main.rs
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
mod engine;
mod server;
use engine::request;
use std::string::String;
use self::serde_json::{Error, Value};
#[derive(Serialize, Deserialize)]
struct obj {
items: Vec<String>,
}
fn main() {
let output_jn: String = request(
"https://api.github.com/search/issues?q=is:issue+label:e-easy",
).to_string(); //gets json structure as string
let json: obj = serde_json::from_str(&output_jn).unwrap();
for elem in json.iter() {
println!("{:?}", elem);
}
}
I get the following error message
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value:
ErrorImpl { code: Message("invalid type: map, expected a sequence"),
line: 1, column: 0 }', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
I'm certain I'm making a stupid mistake in deserializing my JSON structure, I've tried a number of permutations and combinations but I couldn't get anything to work.
Have a look at this part of your JSON input data:
{
...
"items": [
{
...
"title": "Stop setting $CARGO_HOME to its default value",
...
}
]
}
Obj
."items"
so in Rust this will be a field items
inside the Obj
struct."items"
in the map is a JSON array, so in Rust let's use a Vec.Issue
."title"
so this will be a field title
inside the Issue
struct."title"
is a JSON string so we can use Rust's String
type for the field.#[derive(Deserialize, Debug)]
struct Obj {
items: Vec<Issue>,
}
#[derive(Deserialize, Debug)]
struct Issue {
title: String,
}
fn main() {
let j = /* get the JSON data */;
let issues = serde_json::from_str::<Obj>(j).unwrap();
for i in issues.items {
println!("{:#?}", i);
}
}