Skip to content

Commit 4b69b48

Browse files
committed
Updated documentation + minor implementation improvements.
1 parent b129a31 commit 4b69b48

File tree

9 files changed

+923
-45
lines changed

9 files changed

+923
-45
lines changed

guides/getting-started/readme.md

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,60 +14,117 @@ $ bundle add protocol-http
1414

1515
`protocol-http` has several core concepts:
1616

17-
- A {ruby Protocol::HTTP::Request} instance which represents an abstract HTTP request. Specific versions of HTTP may subclass this to track additional state.
18-
- A {ruby Protocol::HTTP::Response} instance which represents an abstract HTTP response. Specific versions of HTTP may subclass this to track additional state.
19-
- A {ruby Protocol::HTTP::Middleware} interface for building HTTP applications.
20-
- A {ruby Protocol::HTTP::Headers} interface for storing HTTP headers with semantics based on documented specifications (RFCs, etc).
21-
- A set of {ruby Protocol::HTTP::Body} classes which handle the internal request and response bodies, including bi-directional streaming.
17+
- A {ruby Protocol::HTTP::Request} instance which represents an abstract HTTP request. Specific versions of HTTP may subclass this to track additional state.
18+
- A {ruby Protocol::HTTP::Response} instance which represents an abstract HTTP response. Specific versions of HTTP may subclass this to track additional state.
19+
- A {ruby Protocol::HTTP::Middleware} interface for building HTTP applications.
20+
- A {ruby Protocol::HTTP::Headers} interface for storing HTTP headers with semantics based on documented specifications (RFCs, etc).
21+
- A set of {ruby Protocol::HTTP::Body} classes which handle the internal request and response bodies, including bi-directional streaming.
2222

2323
## Integration
2424

2525
This gem does not provide any specific client or server implementation, rather it's used by several other gems.
2626

27-
- [Protocol::HTTP1](https://github.com/socketry/protocol-http1) & [Protocol::HTTP2](https://github.com/socketry/protocol-http2) which provide client and server implementations.
28-
- [Async::HTTP](https://github.com/socketry/async-http) which provides connection pooling and concurrency.
27+
- [Protocol::HTTP1](https://github.com/socketry/protocol-http1) & [Protocol::HTTP2](https://github.com/socketry/protocol-http2) which provide client and server implementations.
28+
- [Async::HTTP](https://github.com/socketry/async-http) which provides connection pooling and concurrency.
2929

3030
## Usage
3131

32-
### Headers
32+
### Request
3333

34-
{ruby Protocol::HTTP::Headers} provides semantically meaningful interpretation of header values implements case-normalising keys.
34+
{ruby Protocol::HTTP::Request} represents an HTTP request which can be used both server and client-side.
3535

3636
``` ruby
37-
require 'protocol/http/headers'
37+
require 'protocol/http/request'
3838

39-
headers = Protocol::HTTP::Headers.new
39+
# Short form (recommended):
40+
request = Protocol::HTTP::Request["GET", "/index.html", {"accept" => "text/html"}]
4041

41-
headers['Content-Type'] = "image/jpeg"
42+
# Long form:
43+
headers = Protocol::HTTP::Headers[["accept", "text/html"]]
44+
request = Protocol::HTTP::Request.new("http", "example.com", "GET", "/index.html", "HTTP/1.1", headers)
4245

43-
headers['content-type']
44-
# => "image/jpeg"
46+
# Access request properties
47+
request.method # => "GET"
48+
request.path # => "/index.html"
49+
request.headers # => Protocol::HTTP::Headers instance
4550
```
4651

47-
### Hypertext References
52+
### Response
4853

49-
{ruby Protocol::HTTP::Reference} is used to construct "hypertext references" which consist of a path and URL-encoded key/value pairs.
54+
{ruby Protocol::HTTP::Response} represents an HTTP response which can be used both server and client-side.
5055

5156
``` ruby
52-
require 'protocol/http/reference'
53-
54-
reference = Protocol::HTTP::Reference.new("/search", q: 'kittens')
55-
56-
reference.to_s
57-
# => "/search?q=kittens"
57+
require 'protocol/http/response'
58+
59+
# Short form (recommended):
60+
response = Protocol::HTTP::Response[200, {"content-type" => "text/html"}, "Hello, World!"]
61+
62+
# Long form:
63+
headers = Protocol::HTTP::Headers["content-type" => "text/html"]
64+
body = Protocol::HTTP::Body::Buffered.wrap("Hello, World!")
65+
response = Protocol::HTTP::Response.new("HTTP/1.1", 200, headers, body)
66+
67+
# Access response properties
68+
response.status # => 200
69+
response.headers # => Protocol::HTTP::Headers instance
70+
response.body # => Body instance
71+
72+
# Status checking methods
73+
response.success? # => true (200-299)
74+
response.ok? # => true (200)
75+
response.redirection? # => false (300-399)
76+
response.failure? # => false (400-599)
5877
```
5978

60-
### URL Parsing
79+
### Headers
80+
81+
{ruby Protocol::HTTP::Headers} provides semantically meaningful interpretation of header values and implements case-normalising keys.
6182

62-
{ruby Protocol::HTTP::URL} is used to parse incoming URLs to extract the query and other relevant details.
83+
#### Basic Usage
6384

6485
``` ruby
65-
require 'protocol/http/url'
86+
require 'protocol/http/headers'
6687

67-
reference = Protocol::HTTP::Reference.parse("/search?q=kittens")
88+
headers = Protocol::HTTP::Headers.new
6889

69-
parameters = Protocol::HTTP::URL.decode(reference.query)
70-
# => {"q"=>"kittens"}
90+
# Assignment by title-case key:
91+
headers['Content-Type'] = "image/jpeg"
92+
93+
# Lookup by lower-case (normalized) key:
94+
headers['content-type']
95+
# => "image/jpeg"
7196
```
7297

73-
This implementation may be merged with {ruby Protocol::HTTP::Reference} or removed in the future.
98+
#### Semantic Processing
99+
100+
Many headers receive special semantic processing, automatically splitting comma-separated values and providing structured access:
101+
102+
``` ruby
103+
# Accept header with quality values:
104+
headers['Accept'] = 'text/html, application/json;q=0.8, */*;q=0.1'
105+
accept = headers['accept']
106+
# => ["text/html", "application/json;q=0.8", "*/*;q=0.1"]
107+
108+
# Access parsed media ranges with quality factors:
109+
accept.media_ranges.each do |range|
110+
puts "#{range.type}/#{range.subtype} (q=#{range.quality_factor})"
111+
end
112+
# text/html (q=1.0)
113+
# application/json (q=0.8)
114+
# */* (q=0.1)
115+
116+
# Accept-Encoding automatically splits values:
117+
headers['Accept-Encoding'] = 'gzip, deflate, br;q=0.9'
118+
headers['accept-encoding']
119+
# => ["gzip", "deflate", "br;q=0.9"]
120+
121+
# Cache-Control splits directives:
122+
headers['Cache-Control'] = 'max-age=3600, no-cache, must-revalidate'
123+
headers['cache-control']
124+
# => ["max-age=3600", "no-cache", "must-revalidate"]
125+
126+
# Vary header normalizes field names to lowercase:
127+
headers['Vary'] = 'Accept-Encoding, User-Agent'
128+
headers['vary']
129+
# => ["accept-encoding", "user-agent"]
130+
```

guides/hypertext-references/readme.md

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Hypertext References
2+
3+
This guide explains how to use `Protocol::HTTP::Reference` for constructing and manipulating hypertext references (URLs with parameters).
4+
5+
## Overview
6+
7+
{ruby Protocol::HTTP::Reference} is used to construct "hypertext references" which consist of a path and URL-encoded parameters. References provide a rich API for URL construction, path manipulation, and parameter handling.
8+
9+
## Basic Construction
10+
11+
``` ruby
12+
require 'protocol/http/reference'
13+
14+
# Simple reference with parameters:
15+
reference = Protocol::HTTP::Reference.new("/search", nil, nil, {q: 'kittens', limit: 10})
16+
reference.to_s
17+
# => "/search?q=kittens&limit=10"
18+
19+
# Parse existing URLs:
20+
reference = Protocol::HTTP::Reference.parse("/api/users?page=2&sort=name#results")
21+
reference.path # => "/api/users"
22+
reference.query # => "page=2&sort=name"
23+
reference.fragment # => "results"
24+
25+
# To get parameters as a hash, decode the query string:
26+
parameters = Protocol::HTTP::URL.decode(reference.query)
27+
parameters # => {"page" => "2", "sort" => "name"}
28+
```
29+
30+
## Path Manipulation
31+
32+
References support sophisticated path manipulation including relative path resolution:
33+
34+
``` ruby
35+
base = Protocol::HTTP::Reference.new("/api/v1/users")
36+
37+
# Append paths:
38+
user_detail = base.with(path: "123")
39+
user_detail.to_s # => "/api/v1/users/123"
40+
41+
# Relative path navigation:
42+
parent = user_detail.with(path: "../groups", pop: true)
43+
parent.to_s # => "/api/v1/groups"
44+
45+
# Absolute path replacement:
46+
root = user_detail.with(path: "/status")
47+
root.to_s # => "/status"
48+
```
49+
50+
## Advanced Parameter Handling
51+
52+
``` ruby
53+
# Complex parameter structures:
54+
reference = Protocol::HTTP::Reference.new("/search", nil, nil, {
55+
filters: {
56+
category: "books",
57+
price: {min: 10, max: 50}
58+
},
59+
tags: ["fiction", "mystery"]
60+
})
61+
62+
reference.to_s
63+
# => "/search?filters[category]=books&filters[price][min]=10&filters[price][max]=50&tags[]=fiction&tags[]=mystery"
64+
65+
# Parameter merging:
66+
base = Protocol::HTTP::Reference.new("/api", nil, nil, {version: "v1", format: "json"})
67+
extended = base.with(parameters: {detailed: true}, merge: true)
68+
extended.to_s
69+
# => "/api?version=v1&format=json&detailed=true"
70+
71+
# Parameter replacement (using merge: false):
72+
replaced = base.with(parameters: {format: "xml"}, merge: false)
73+
replaced.to_s
74+
# => "/api?format=xml"
75+
```
76+
77+
## Merge Behavior and Query Strings
78+
79+
The `merge` parameter controls both parameter handling and query string behavior:
80+
81+
``` ruby
82+
# Create a reference with both query string and parameters:
83+
ref = Protocol::HTTP::Reference.new("/api", "existing=query", nil, {version: "v1"})
84+
ref.to_s
85+
# => "/api?existing=query&version=v1"
86+
87+
# merge: true (default) - keeps existing query string:
88+
merged = ref.with(parameters: {new: "argument"}, merge: true)
89+
merged.to_s
90+
# => "/api?existing=query&version=v1&new=argument"
91+
92+
# merge: false with new parameters - clears query string:
93+
replaced = ref.with(parameters: {new: "argument"}, merge: false)
94+
replaced.to_s
95+
# => "/api?new=argument"
96+
97+
# merge: false without new parameters - keeps everything:
98+
unchanged = ref.with(path: "v2", merge: false)
99+
unchanged.to_s
100+
# => "/api/v2?existing=query&version=v1"
101+
```
102+
103+
## URL Encoding and Special Characters
104+
105+
References handle URL encoding automatically:
106+
107+
``` ruby
108+
# Spaces and special characters:
109+
reference = Protocol::HTTP::Reference.new("/search", nil, nil, {
110+
q: "hello world",
111+
filter: "price > $10"
112+
})
113+
reference.to_s
114+
# => "/search?q=hello%20world&filter=price%20%3E%20%2410"
115+
116+
# Unicode support:
117+
unicode_ref = Protocol::HTTP::Reference.new("/files", nil, nil, {
118+
name: "résumé.pdf",
119+
emoji: "😀"
120+
})
121+
unicode_ref.to_s
122+
# => "/files?name=r%C3%A9sum%C3%A9.pdf&emoji=%F0%9F%98%80"
123+
```
124+
125+
## Reference Merging
126+
127+
References can be merged following RFC2396 URI resolution rules:
128+
129+
``` ruby
130+
base = Protocol::HTTP::Reference.new("/docs/guide/")
131+
relative = Protocol::HTTP::Reference.new("../api/reference.html")
132+
133+
merged = base + relative
134+
merged.to_s # => "/docs/api/reference.html"
135+
136+
# Absolute references override completely
137+
absolute = Protocol::HTTP::Reference.new("/completely/different/path")
138+
result = base + absolute
139+
result.to_s # => "/completely/different/path"
140+
```

guides/links.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
getting-started:
22
order: 1
3+
message-body:
4+
order: 2
5+
middleware:
6+
order: 3
7+
hypertext-references:
8+
order: 4
9+
url-parsing:
10+
order: 5
11+
streaming:
12+
order: 6
313
design-overview:
414
order: 10

0 commit comments

Comments
 (0)