/// <summary> /// Trigger the build and output of Posts to the STDOUT stream /// </summary> public void Handle(Options options, IConsoleStream consoleStream) { // Validate that the number of Posts does not exceed 100 if (options.Posts < 1 || options.Posts > 100) { consoleStream.WriteErrorLine("Number of posts must be a positive integer not exceeding 100"); return; } var postSerializer = new JsonSerializer(); consoleStream.JsonWriter.Formatting = Formatting.Indented; int postCounter = 1; // Write the start of the Json Array to the STDOUT stream consoleStream.JsonWriter.WriteStartArray(); // Write each post to the Array in the STDOUT stream // This continues to use Linq Lazy Evaluation to write one valid post to the STDOUT stream // at a time var posts = service.GetTopPosts(consoleStream) .Where(PostValidator.Validate) .Where(p => SerializePost(postSerializer, consoleStream, p, postCounter++)) .Take(options.Posts) .ToList(); // Write the end of the Json Array to the STDOUT stream consoleStream.JsonWriter.WriteEndArray(); }
/// <summary> /// Makes an API call to get the collection of Top Story Ids /// </summary> private IEnumerable <long> GetTopPostIdCollection(IConsoleStream consoleStream) { IEnumerable <long> storyIds = new List <long>().AsEnumerable(); try { var response = client.GetAsync(new Uri("https://hacker-news.firebaseio.com/v0/topstories.json")).Result; var jsonString = response.Content.ReadAsStringAsync().Result; storyIds = JsonConvert.DeserializeObject <IEnumerable <long> >(jsonString); } catch (Exception e) { consoleStream.WriteErrorLine("Error getting latest Post Ids"); consoleStream.WriteErrorLine(e.Message); } return(storyIds); }
/// <summary> /// Method to write a Post in the required format to the STDOUT stream /// </summary> private bool SerializePost(JsonSerializer ser, IConsoleStream consoleStream, Post post, int counter) { try { ser.Serialize(consoleStream.JsonWriter, new { title = post.title, uri = post.url, author = post.by, points = post.score, comments = post.descendants, rank = counter }); } catch (Exception e) { consoleStream.WriteErrorLine(e.Message); return(false); } return(true); }
/// <summary> /// First gets the list of top story Ids and then calls the API for each Id to get the full story data. /// This method takes advantage of LazyEvaluation which only executes the API call when needed. /// </summary> public IEnumerable <Post> GetTopPosts(IConsoleStream consoleStream) { var postIds = GetTopPostIdCollection(consoleStream); foreach (var id in postIds) { Post post = null; try { var response = client.GetAsync(new Uri($"https://hacker-news.firebaseio.com/v0/item/{id}.json")).Result; var jsonString = response.Content.ReadAsStringAsync().Result; post = JsonConvert.DeserializeObject <Post>(jsonString); } catch (Exception e) { consoleStream.WriteErrorLine($"Error getting Post for Post Id: {id}"); consoleStream.WriteErrorLine(e.Message); continue; } yield return(post); } }