2929//! }
3030//! ```
3131
32+ use rustapi_openapi:: Schema ;
3233use serde:: { Deserialize , Serialize } ;
3334use std:: collections:: HashMap ;
3435
@@ -37,14 +38,14 @@ use std::collections::HashMap;
3738/// Links provide navigation between related resources.
3839///
3940/// # Example
40- /// ```rust
41+ /// ```rust,ignore
4142/// use rustapi_core::hateoas::Link;
4243///
4344/// let link = Link::new("/users/123")
4445/// .title("User details")
4546/// .set_templated(false);
4647/// ```
47- #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
48+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Schema ) ]
4849pub struct Link {
4950 /// The URI of the linked resource
5051 pub href : String ,
@@ -157,7 +158,7 @@ impl Link {
157158/// Wraps any data type with `_links` and optional `_embedded` sections.
158159///
159160/// # Example
160- /// ```rust
161+ /// ```rust,ignore
161162/// use rustapi_core::hateoas::Resource;
162163/// use serde::Serialize;
163164///
@@ -172,8 +173,8 @@ impl Link {
172173/// .self_link("/users/1")
173174/// .link("orders", "/users/1/orders");
174175/// ```
175- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
176- pub struct Resource < T > {
176+ #[ derive( Debug , Clone , Serialize , Deserialize , Schema ) ]
177+ pub struct Resource < T : rustapi_openapi :: schema :: RustApiSchema > {
177178 /// The actual resource data (flattened into the JSON)
178179 #[ serde( flatten) ]
179180 pub data : T ,
@@ -188,7 +189,7 @@ pub struct Resource<T> {
188189}
189190
190191/// Either a single link or an array of links
191- #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
192+ #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq , Schema ) ]
192193#[ serde( untagged) ]
193194pub enum LinkOrArray {
194195 /// Single link
@@ -209,7 +210,7 @@ impl From<Vec<Link>> for LinkOrArray {
209210 }
210211}
211212
212- impl < T > Resource < T > {
213+ impl < T : rustapi_openapi :: schema :: RustApiSchema > Resource < T > {
213214 /// Create a new resource wrapper
214215 pub fn new ( data : T ) -> Self {
215216 Self {
@@ -268,7 +269,7 @@ impl<T> Resource<T> {
268269/// navigation links.
269270///
270271/// # Example
271- /// ```rust
272+ /// ```rust,ignore
272273/// use rustapi_core::hateoas::{ResourceCollection, PageInfo};
273274/// use serde::Serialize;
274275///
@@ -288,8 +289,8 @@ impl<T> Resource<T> {
288289/// .next_link("/users?page=2")
289290/// .page_info(PageInfo::new(20, 100, 5, 1));
290291/// ```
291- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
292- pub struct ResourceCollection < T > {
292+ #[ derive( Debug , Clone , Serialize , Deserialize , Schema ) ]
293+ pub struct ResourceCollection < T : rustapi_openapi :: schema :: RustApiSchema > {
293294 /// Embedded resources
294295 #[ serde( rename = "_embedded" ) ]
295296 pub embedded : HashMap < String , Vec < T > > ,
@@ -304,7 +305,7 @@ pub struct ResourceCollection<T> {
304305}
305306
306307/// Pagination information
307- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
308+ #[ derive( Debug , Clone , Serialize , Deserialize , Schema ) ]
308309pub struct PageInfo {
309310 /// Number of items per page
310311 pub size : usize ,
@@ -341,7 +342,7 @@ impl PageInfo {
341342 }
342343}
343344
344- impl < T > ResourceCollection < T > {
345+ impl < T : rustapi_openapi :: schema :: RustApiSchema > ResourceCollection < T > {
345346 /// Create a new resource collection
346347 pub fn new ( rel : impl Into < String > , items : Vec < T > ) -> Self {
347348 let mut embedded = HashMap :: new ( ) ;
@@ -436,19 +437,20 @@ impl<T> ResourceCollection<T> {
436437}
437438
438439/// Helper trait for adding HATEOAS links to any type
439- pub trait Linkable : Sized + Serialize {
440+ pub trait Linkable : Sized + Serialize + rustapi_openapi :: schema :: RustApiSchema {
440441 /// Wrap this value in a Resource with HATEOAS links
441442 fn with_links ( self ) -> Resource < Self > {
442443 Resource :: new ( self )
443444 }
444445}
445446
446- // Implement Linkable for all Serialize types
447- impl < T : Serialize > Linkable for T { }
447+ // Implement Linkable for all Serialize + Schema types
448+ impl < T : Serialize + rustapi_openapi :: schema :: RustApiSchema > Linkable for T { }
448449
449450#[ cfg( test) ]
450451mod tests {
451452 use super :: * ;
453+ use rustapi_openapi:: schema:: { JsonSchema2020 , RustApiSchema , SchemaCtx , SchemaRef } ;
452454 use serde:: Serialize ;
453455
454456 #[ derive( Debug , Clone , Serialize , Deserialize , PartialEq ) ]
@@ -457,6 +459,20 @@ mod tests {
457459 name : String ,
458460 }
459461
462+ impl RustApiSchema for User {
463+ fn schema ( _: & mut SchemaCtx ) -> SchemaRef {
464+ let mut s = JsonSchema2020 :: object ( ) ;
465+ let mut props = std:: collections:: BTreeMap :: new ( ) ;
466+ props. insert ( "id" . to_string ( ) , JsonSchema2020 :: integer ( ) ) ;
467+ props. insert ( "name" . to_string ( ) , JsonSchema2020 :: string ( ) ) ;
468+ s. properties = Some ( props) ;
469+ SchemaRef :: Schema ( Box :: new ( s) )
470+ }
471+ fn name ( ) -> std:: borrow:: Cow < ' static , str > {
472+ std:: borrow:: Cow :: Borrowed ( "User" )
473+ }
474+ }
475+
460476 #[ test]
461477 fn test_link_creation ( ) {
462478 let link = Link :: new ( "/users/1" )
0 commit comments