OCaml library for JSONfeed parsing and creation
1(** Example: Creating and serializing a JSON Feed 2 3 This demonstrates: 4 - Creating authors 5 - Creating items with different content types 6 - Creating a complete feed 7 - Serializing to JSON string and file *) 8 9open Jsonfeed 10 11(* Helper to write feed to Eio flow *) 12let to_flow flow feed = 13 let s = Jsonfeed.to_string feed in 14 Eio.Flow.copy_string s flow 15 16let create_blog_feed () = 17 (* Create some authors *) 18 let jane = Author.create 19 ~name:"Jane Doe" 20 ~url:"https://example.com/authors/jane" 21 ~avatar:"https://example.com/avatars/jane.png" 22 () in 23 24 let john = Author.create 25 ~name:"John Smith" 26 ~url:"https://example.com/authors/john" 27 () in 28 29 (* Create items with different content types *) 30 let item1 = Item.create 31 ~id:"https://example.com/posts/1" 32 ~url:"https://example.com/posts/1" 33 ~title:"Introduction to OCaml" 34 ~content:(`Both ( 35 "<p>OCaml is a powerful functional programming language.</p>", 36 "OCaml is a powerful functional programming language." 37 )) 38 ~date_published:(Jsonfeed.parse_rfc3339 "2024-11-01T10:00:00Z" |> Option.get) 39 ~date_modified:(Jsonfeed.parse_rfc3339 "2024-11-01T15:30:00Z" |> Option.get) 40 ~authors:[jane] 41 ~tags:["ocaml"; "programming"; "functional"] 42 ~summary:"A beginner's guide to OCaml programming" 43 () in 44 45 let item2 = Item.create 46 ~id:"https://example.com/posts/2" 47 ~url:"https://example.com/posts/2" 48 ~title:"JSON Feed for Syndication" 49 ~content:(`Html "<p>JSON Feed is a modern alternative to RSS and Atom.</p>") 50 ~date_published:(Jsonfeed.parse_rfc3339 "2024-11-02T09:00:00Z" |> Option.get) 51 ~authors:[jane; john] 52 ~tags:["json"; "syndication"; "web"] 53 ~image:"https://example.com/images/jsonfeed.png" 54 () in 55 56 (* Microblog-style item (text only, no title) *) 57 let item3 = Item.create 58 ~id:"https://example.com/micro/42" 59 ~content:(`Text "Just shipped a new feature! 🚀") 60 ~date_published:(Jsonfeed.parse_rfc3339 "2024-11-03T08:15:00Z" |> Option.get) 61 ~tags:["microblog"] 62 () in 63 64 (* Create the complete feed *) 65 let feed = Jsonfeed.create 66 ~title:"Example Blog" 67 ~home_page_url:"https://example.com" 68 ~feed_url:"https://example.com/feed.json" 69 ~description:"A blog about programming, web development, and technology" 70 ~icon:"https://example.com/icon-512.png" 71 ~favicon:"https://example.com/favicon-64.png" 72 ~authors:[jane; john] 73 ~language:"en-US" 74 ~items:[item1; item2; item3] 75 () in 76 77 feed 78 79let create_podcast_feed () = 80 (* Create podcast author *) 81 let host = Author.create 82 ~name:"Podcast Host" 83 ~url:"https://podcast.example.com/host" 84 ~avatar:"https://podcast.example.com/host-avatar.jpg" 85 () in 86 87 (* Create episode with audio attachment *) 88 let attachment = Attachment.create 89 ~url:"https://podcast.example.com/episodes/ep1.mp3" 90 ~mime_type:"audio/mpeg" 91 ~title:"Episode 1: Introduction" 92 ~size_in_bytes:15_728_640L 93 ~duration_in_seconds:1800 94 () in 95 96 let episode = Item.create 97 ~id:"https://podcast.example.com/episodes/1" 98 ~url:"https://podcast.example.com/episodes/1" 99 ~title:"Episode 1: Introduction" 100 ~content:(`Html "<p>Welcome to our first episode!</p>") 101 ~date_published:(Jsonfeed.parse_rfc3339 "2024-11-01T12:00:00Z" |> Option.get) 102 ~attachments:[attachment] 103 ~authors:[host] 104 ~image:"https://podcast.example.com/episodes/ep1-cover.jpg" 105 () in 106 107 (* Create podcast feed with hub for real-time updates *) 108 let hub = Hub.create 109 ~type_:"WebSub" 110 ~url:"https://pubsubhubbub.appspot.com/" 111 () in 112 113 let feed = Jsonfeed.create 114 ~title:"Example Podcast" 115 ~home_page_url:"https://podcast.example.com" 116 ~feed_url:"https://podcast.example.com/feed.json" 117 ~description:"A podcast about interesting topics" 118 ~icon:"https://podcast.example.com/icon.png" 119 ~authors:[host] 120 ~language:"en-US" 121 ~hubs:[hub] 122 ~items:[episode] 123 () in 124 125 feed 126 127let main () = 128 Eio_main.run @@ fun env -> 129 130 (* Create blog feed *) 131 let blog_feed = create_blog_feed () in 132 Format.printf "Created blog feed: %a\n\n" Jsonfeed.pp blog_feed; 133 134 (* Serialize to string *) 135 let json_string = Jsonfeed.to_string blog_feed in 136 Format.printf "JSON (first 200 chars): %s...\n\n" 137 (String.sub json_string 0 (min 200 (String.length json_string))); 138 139 (* Serialize to file *) 140 let feed_path = Eio.Path.(env#fs / "blog-feed.json") in 141 Eio.Path.with_open_out ~create:(`Or_truncate 0o644) feed_path @@ fun flow -> 142 to_flow (flow :> Eio.Flow.sink_ty Eio.Resource.t) blog_feed; 143 Format.printf "Wrote blog feed to blog-feed.json\n\n"; 144 145 (* Create podcast feed *) 146 let podcast_feed = create_podcast_feed () in 147 Format.printf "Created podcast feed: %a\n\n" Jsonfeed.pp_summary podcast_feed; 148 149 (* Validate feeds *) 150 (match Jsonfeed.validate blog_feed with 151 | Ok () -> Format.printf "✓ Blog feed is valid\n" 152 | Error errors -> 153 Format.printf "✗ Blog feed validation errors:\n"; 154 List.iter (Format.printf " - %s\n") errors); 155 156 (match Jsonfeed.validate podcast_feed with 157 | Ok () -> Format.printf "✓ Podcast feed is valid\n" 158 | Error errors -> 159 Format.printf "✗ Podcast feed validation errors:\n"; 160 List.iter (Format.printf " - %s\n") errors) 161 162let () = main ()