github.com/rpdict/ponzu@v0.10.1-0.20190226054626-477f29d6bf5e/docs/src/References/Overview.md (about) 1 title: References in Ponzu 2 3 References in Ponzu allow you to create relationships between your Content types. 4 Ponzu uses an embedded database, rather than a more traditional relational database 5 with SQL support. This may seem unnatural since there is no native concept of 6 "foreign keys" or "joins" like you may be used to. Instead, Ponzu wires up your 7 data using references, which are simply URL paths, like `/api/content?type=Post&id=1` 8 9 A foreign key as a URL path?! Am I crazy? No! For the purpose Ponzu serves, 10 this structure works quite well, especially given its creation was specifically 11 tuned for HTTP/2 features such as "Request/Response Multiplexing" and "Server Push." 12 13 There is a deeper dive into the HTTP/2 concepts [below](/References/Overview/#designed-for-http2), but first we'll walk through 14 a quick tutorial on Ponzu's references. 15 16 To generate references from the CLI, please [read through the documentation](/CLI/Generating-References). 17 The example below assumes you understand the syntax. 18 19 --- 20 21 ### Create Your Content Types 22 23 Here we are creating two Content types, `Author` and `Book`. A `Book` will keep 24 a reference to an `Author` in the sense that an author wrote the book. 25 26 ```bash 27 $ ponzu gen c author name:string photo:string:file bio:string:textarea 28 $ ponzu gen c book title:string author:@author,name pages:int year:int 29 ``` 30 31 The structs generated for each look like: 32 33 `content/author.go` 34 ```go 35 type Author struct { 36 item.Item 37 38 Name string `json:"name"` 39 Photo string `json:"photo"` 40 Bio string `json:"bio"` 41 } 42 ``` 43 44 `content/book.go` 45 ```go 46 type Book struct { 47 item.Item 48 49 Title string `json:"title"` 50 Author string `json:"author"` 51 Pages int `json:"pages"` 52 Year int `json:"year"` 53 } 54 ``` 55 56 Notice how the `Author` field within the `Book` struct is a `string` type, not 57 an `Author` type. This is because the `Author` is stored as a `string` in our 58 database, as a reference to the `Author`, instead of embedding the `Author` data 59 inside the `Book`. 60 61 Some example JSON data for the two structs looks like: 62 63 <kbd>GET</kbd> `/api/content?type=Author&id=1` (`Author`) 64 ```json 65 { 66 "data": [ 67 { 68 "uuid": "024a5797-e064-4ee0-abe3-415cb6d3ed18", 69 "id": 1, 70 "slug": "item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18", 71 "timestamp": 1493926453826, 72 "updated": 1493926453826, 73 "name": "Shel Silverstein", 74 "photo": "/api/uploads/2017/05/shel-silverstein.jpg", 75 "bio": "Sheldon Allan Silverstein was an American poet..." 76 } 77 ] 78 } 79 ``` 80 81 <kbd>GET</kbd> `/api/content?type=Book&id=1` (`Book`) 82 ```json 83 { 84 "data": [ 85 { 86 "uuid": "024a5797-e064-4ee0-abe3-415cb6d3ed18", 87 "id": 1, 88 "slug": "item-id-024a5797-e064-4ee0-abe3-415cb6d3ed18", 89 "timestamp": 1493926453826, 90 "updated": 1493926453826, 91 "title": "The Giving Tree", 92 "author": "/api/content?type=Author&id=1", 93 "pages": 57, 94 "year": 1964 95 } 96 ] 97 } 98 ``` 99 100 As you can see, the `Author` is a reference as the `author` field in the JSON 101 response for a `Book`. When you're building your client, you need to make a second 102 request for the `Author`, to the URL path found in the `author` field of the `Book` 103 response. 104 105 For example, in pseudo-code: 106 ```bash 107 # Request 1: 108 $book = GET /api/content?type=Book&id=1 109 110 # Request 2: 111 $author = GET $book.author # where author = /api/content?type=Author&id=1 112 ``` 113 114 Until recently, this would be considered bad practice and would be costly to do 115 over HTTP. However, with the wide availability of HTTP/2 clients, including all 116 modern web browsers, mobile devices, and HTTP/2 libraries in practically every 117 programming language, this pattern is fast and scalable. 118 119 --- 120 121 ### Designed For HTTP/2 122 123 At this point, you've likely noticed that you're still making two independent 124 HTTP requests to your Ponzu server. Further, if there are multiple references or more 125 than one item, you'll be making many requests -- _how can that be efficient?_ 126 127 There are two main concepts at play: Request/Response Multiplexing and Server Push. 128 129 #### Request/Response Multiplexing 130 131 With HTTP/2, a client and server (peers) transfer data over a single TCP connection, 132 and can send data back and forth at the same time. No longer does a request need 133 to wait to be sent until after an expected response is read. This means that HTTP 134 requests can be sent much faster and at the _same time_ on a single connection. 135 Where previously, a client would open up several TCP connections, the re-use of a 136 single connection reduces CPU overhead and makes the server more efficient. 137 138 This feature is automatically provided to you when using HTTP/2 - the only 139 requirement is that you connect via HTTPS and have active TLS certificates, which 140 you can get for free by running Ponzu with the `--https` flag and configuring it 141 with a properly set, active domain name of your own. 142 143 #### Server Push 144 145 Another impactful feature of HTTP/2 is "Server Push": the ability to preemptively 146 send a response from the server to a client without waiting for a request. This 147 is where Ponzu's reference design really shows it's power. Let's revisit the 148 example from above: 149 150 ```bash 151 # Request 1: 152 $book = GET /api/content?type=Book&id=1 153 154 # Request 2: 155 $author = GET $book.author # where author = /api/content?type=Author&id=1 156 ``` 157 158 Instead of waiting for the server to respond with the data for `$book.author`, 159 the response data is already in the client's cache before we even make the request! 160 Now there is no round-trip made to the server and back, and the client reads the 161 pushed response from cache in fractions of a millisecond. 162 163 But, how does the server know which response to push and when? You'll need to 164 specify which fields of the type you've requested should be pushed. This is done 165 by implementing the [`item.Pushable` interface](/Interfaces/Item#itempushable). 166 See the example below which demonstrates a complete implementation on the `Book` 167 struct, which has a reference to an `Author`. 168 169 ##### Example 170 171 `content/book.go` 172 ```go 173 ... 174 type Book struct { 175 item.Item 176 177 Title string `json:"title"` 178 Author string `json:"author"` 179 Pages int `json:"pages"` 180 Year int `json:"year"` 181 } 182 183 184 func (b *Book) Push(res http.ResponseWriter, req *http.Request) ([]string, error) { 185 return []string{ 186 // the json struct tag is used to tell the server which 187 // field(s) it should push - only URL paths originating 188 // from your server can be pushed! 189 "author", 190 }, nil 191 } 192 ... 193 ``` 194 195 Now, whenever a single `Book` is requested, the server will preemptively push the 196 `Author` referenced by the book. The response for the `Author` will _already be 197 on the client_ and will remain there until a request for the referenced `Author` 198 has been made. 199 200 !!! note "What else can I Push?" 201 Only fields that are URL paths originating from your server can be pushed. 202 This means that you could also implement `item.Pushable` on the `Author` 203 type, and return `[]string{"photo"}, nil` to push the Author's image! 204 205 --- 206 207 ### Other Considerations 208 209 HTTP/2 Server Push is a powerful feature, but it can be abused just like anything 210 else. To try and help mitigate potential issues, Ponzu has put some "stop-gaps" 211 in place. Server Push is only activated on **single item** API responses, so you 212 shouldn't expect to see references or files pushed from the `/api/contents` endpoint. 213 An exception to this is the `/api/search` endpoint, which only the **first** 214 result is pushed (if applicable) no matter how many items are in the response. 215 216 You should take advantage of HTTP/2 in Ponzu and get the most out of the system. 217 With the automatic HTTPS feature, there is no reason not to and you gain the 218 additional benefit of encrypting your traffic - which your users will appreciate!