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!