OCaml library for JSONfeed parsing and creation
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** JSON Feed format parser and serializer. 7 8 @see <https://www.jsonfeed.org/version/1.1/> JSON Feed Specification *) 9 10type t 11(** The type representing a complete JSON Feed. *) 12 13val jsont : t Jsont.t 14(** Declarative type that describes the structure of JSON Feeds. 15 16 Maps the complete JSON Feed 1.1 specification including all required and 17 optional fields. *) 18 19module Unknown : sig 20 type t = Jsont.json 21 (** Unknown or unrecognized JSON object members as a generic JSON object. 22 Useful for preserving fields from custom extensions or future spec 23 versions. *) 24 25 val empty : t 26 (** [empty] is the empty list of unknown fields. *) 27 28 val is_empty : t -> bool 29 (** [is_empty u] returns [true] if there are no unknown fields. *) 30end 31 32(** {1 Construction} *) 33 34val create : 35 title:string -> 36 ?home_page_url:string -> 37 ?feed_url:string -> 38 ?description:string -> 39 ?user_comment:string -> 40 ?next_url:string -> 41 ?icon:string -> 42 ?favicon:string -> 43 ?authors:Author.t list -> 44 ?language:string -> 45 ?expired:bool -> 46 ?hubs:Hub.t list -> 47 items:Item.t list -> 48 ?unknown:Unknown.t -> 49 unit -> 50 t 51(** [create ~title ~items ()] creates a new JSON Feed. 52 53 @param title 54 The name of the feed. Required field that should be plain text, not HTML. 55 @param home_page_url 56 The URL of the resource that the feed describes. This resource may or may 57 not actually be a "home" page, but it should be an HTML page. If a feed is 58 for a podcast, for instance, the home_page_url would be the URL for the 59 podcast's website. 60 @param feed_url 61 The URL of the feed itself. This is the URL that was requested to get this 62 JSON Feed response. Helps feed readers to determine when they're being 63 redirected. Strongly recommended for feeds. 64 @param description 65 A plain text description of the feed, for human consumption. May contain 66 some formatting (like newlines). 67 @param user_comment 68 A description of the purpose of the feed, for a person looking at the raw 69 JSON. This is for the publisher's use only, not intended to be displayed 70 to the user. 71 @param next_url 72 The URL of a feed that provides the next n items, where n is determined by 73 the publisher. Used for pagination. A feed reader may continue to request 74 the URLs in next_url until it reaches a feed without a next_url. 75 @param icon 76 The URL of an image for the feed suitable to be used in a timeline, much 77 the way an avatar might be used. Should be square and relatively large - 78 such as 512 x 512 pixels - and may be cropped to a circle or rounded 79 corners. Should not be transparent. 80 @param favicon 81 The URL of an image for the feed suitable to be used in a source list. 82 Should be square and relatively small - such as 64 x 64 pixels. Should not 83 be transparent. 84 @param authors 85 Specifies one or more feed authors. The author object has several members 86 (name, url, avatar) which are all optional, but at least one must be 87 present for the object to be valid. 88 @param language 89 The primary language for the feed in RFC 5646 format. The value can be a 90 language tag such as "en" or "en-US", or a language-region combination. 91 @param expired 92 Whether or not the feed is finished - that is, whether or not it will ever 93 update again. A feed for a temporary event, like an instance of a 94 conference, may expire. If the value is [true], feed readers may stop 95 checking for updates. 96 @param hubs 97 Endpoints that can be used to subscribe to real-time notifications from 98 the publisher of this feed. Each hub object has a type (such as "rssCloud" 99 or "WebSub") and url. 100 @param items 101 The items in the feed. Required field, though it may be an empty array. 102 @param unknown 103 Unknown JSON object members preserved from parsing. Useful for custom 104 extensions. *) 105 106(** {1 Accessors} *) 107 108val version : t -> string 109(** [version feed] returns the URL of the version of the format the feed uses. 110 This will always be "https://jsonfeed.org/version/1.1" for feeds created 111 with this library. This is a required field in the JSON Feed spec. *) 112 113val title : t -> string 114(** [title feed] returns the name of the feed. This is plain text and should not 115 contain HTML. This is a required field. *) 116 117val home_page_url : t -> string option 118(** [home_page_url feed] returns the URL of the resource that the feed 119 describes. This resource may or may not actually be a "home" page, but it 120 should be an HTML page. For instance, if a feed is for a podcast, the 121 home_page_url would be the URL for the podcast's website. *) 122 123val feed_url : t -> string option 124(** [feed_url feed] returns the URL of the feed itself. This should be the URL 125 that was requested to get this JSON Feed response. It helps feed readers 126 determine when they're being redirected. This is strongly recommended for 127 feeds. *) 128 129val description : t -> string option 130(** [description feed] returns a plain text description of the feed, for human 131 consumption. This field may contain some formatting such as newlines. *) 132 133val user_comment : t -> string option 134(** [user_comment feed] returns a description of the purpose of the feed, for a 135 person looking at the raw JSON. This is for the publisher's use only and is 136 not intended to be displayed to end users. *) 137 138val next_url : t -> string option 139(** [next_url feed] returns the URL of a feed that provides the next n items, 140 where n is determined by the publisher. This is used for pagination. A feed 141 reader may continue to request the URLs in next_url until it reaches a feed 142 without a next_url. *) 143 144val icon : t -> string option 145(** [icon feed] returns the URL of an image for the feed suitable to be used in 146 a timeline, much the way an avatar might be used. It should be square and 147 relatively large (such as 512 x 512 pixels) and may be cropped to a circle 148 or rounded corners by feed readers. It should not be transparent. *) 149 150val favicon : t -> string option 151(** [favicon feed] returns the URL of an image for the feed suitable to be used 152 in a source list. It should be square and relatively small (such as 64 x 64 153 pixels) and should not be transparent. *) 154 155val authors : t -> Author.t list option 156(** [authors feed] returns the feed authors. Each author object has several 157 members (name, url, avatar) which are all optional, but at least one must be 158 present for the object to be valid. If a feed has multiple authors, they 159 should all be listed here. *) 160 161val language : t -> string option 162(** [language feed] returns the primary language for the feed in RFC 5646 163 format. The value can be a language tag such as "en" or "en-US", or a 164 language-region combination. This field helps feed readers present the feed 165 in the appropriate language. *) 166 167val expired : t -> bool option 168(** [expired feed] returns whether the feed is finished - that is, whether it 169 will ever update again. A feed for a temporary event, like an instance of a 170 conference, may expire. If the value is [Some true], feed readers may stop 171 checking for updates. *) 172 173val hubs : t -> Hub.t list option 174(** [hubs feed] returns endpoints that can be used to subscribe to real-time 175 notifications from the publisher of this feed. Each hub object has a type 176 (such as "rssCloud" or "WebSub") and a url. Feed readers can use these to 177 get immediate updates when new items are published. *) 178 179val items : t -> Item.t list 180(** [items feed] returns the array of items in the feed. This is a required 181 field, though it may be an empty list. Items represent the individual 182 entries in the feed - blog posts, podcast episodes, microblog posts, etc. *) 183 184val unknown : t -> Unknown.t 185(** [unknown feed] returns any unknown JSON object members that were preserved 186 during parsing. This is useful for custom extensions or fields from future 187 versions of the spec. *) 188 189(** {1 Encoding and Decoding} *) 190 191val decode : 192 ?layout:bool -> 193 ?locs:bool -> 194 ?file:string -> 195 Bytesrw.Bytes.Reader.t -> 196 (t, Jsont.Error.t) result 197(** [decode r] decodes a JSON Feed from bytesrw reader [r]. 198 199 @param layout Preserve whitespace for round-tripping (default: false) 200 @param locs Track locations for better error messages (default: false) 201 @param file Source file name for error reporting *) 202 203val decode_string : 204 ?layout:bool -> 205 ?locs:bool -> 206 ?file:string -> 207 string -> 208 (t, Jsont.Error.t) result 209(** [decode_string s] decodes a JSON Feed from string [s]. *) 210 211val encode : 212 ?format:Jsont.format -> 213 ?number_format:Jsont.number_format -> 214 t -> 215 eod:bool -> 216 Bytesrw.Bytes.Writer.t -> 217 (unit, Jsont.Error.t) result 218(** [encode feed w] encodes [feed] to bytesrw writer [w]. 219 220 @param format 221 Output formatting: [Jsont.Minify] or [Jsont.Indent] (default: Minify) 222 @param number_format Printf format for numbers (default: "%.16g") 223 @param eod Write end-of-data marker *) 224 225val encode_string : 226 ?format:Jsont.format -> 227 ?number_format:Jsont.number_format -> 228 t -> 229 (string, Jsont.Error.t) result 230(** [encode_string feed] encodes [feed] to a string. *) 231 232val of_string : string -> (t, Jsont.Error.t) result 233(** Alias for [decode_string] with default options. *) 234 235val to_string : ?minify:bool -> t -> (string, Jsont.Error.t) result 236(** [to_string feed] encodes [feed] to string. 237 @param minify Use compact format (true) or indented (false, default) *) 238 239(** {1 Validation} *) 240 241val validate : t -> (unit, string list) result 242(** [validate feed] validates the feed structure. Checks for unique item IDs, 243 valid content, etc. *) 244 245(** {1 Comparison} *) 246 247val equal : t -> t -> bool 248(** [equal a b] tests equality between two feeds. *) 249 250(** {1 Pretty Printing} *) 251 252val pp : Format.formatter -> t -> unit 253val pp_summary : Format.formatter -> t -> unit 254 255(** {1 Submodules} *) 256 257module Rfc3339 = Rfc3339 258module Cito = Cito 259module Author = Author 260module Attachment = Attachment 261module Hub = Hub 262module Reference = Reference 263module Item = Item