resteze 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CLAUDE.md +74 -0
- data/README.md +31 -0
- data/docs/ADVANCED_USAGE.md +760 -0
- data/docs/API.md +410 -0
- data/docs/CONFIGURATION.md +681 -0
- data/docs/ERROR_HANDLING.md +609 -0
- data/docs/TESTING.md +768 -0
- data/lib/resteze/client.rb +1 -0
- data/lib/resteze/instrumentation.rb +14 -0
- data/lib/resteze/version.rb +1 -1
- data/lib/resteze.rb +2 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55dfa62b10235fa805a820a3c8a11fc01126141941c3dce30b54b62b484a2e18
|
|
4
|
+
data.tar.gz: 7b69653ef28303f319cb56b7bf94ff59cf09291aa3a9911d52158b71df026bb2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ab516cd48e257b13bd1996e0bfd0f5c91a0fceb60e61c6883034f5ff898c560ce615a899f7759ef927e2a2dbd2652ec4d007eba05c235c0ba653b8b230b0a85c
|
|
7
|
+
data.tar.gz: df4fd41077a6555453a95d0786a05f378d1f466e78a47913d563605801d53c054741881e7da2c3dfc6923b23563d7fe8701fdd2d8c71aead5d269d74f7075cb1
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## About
|
|
6
|
+
|
|
7
|
+
Resteze is a Ruby gem that provides a framework for building REST API client libraries. Consumers `include Resteze` in their own module and get a fully namespaced set of classes (Client, ApiResource, ListObject, Error hierarchy, etc.) that they extend to define resources.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bundle exec rake # Run tests + RuboCop (default task)
|
|
13
|
+
bundle exec rake test # Run tests only
|
|
14
|
+
bundle exec rake rubocop # Lint only
|
|
15
|
+
bundle exec ruby -Ilib:test test/resteze/client_test.rb # Run a single test file
|
|
16
|
+
bundle exec guard # Watch mode: re-runs tests on file changes
|
|
17
|
+
COVERAGE=1 bundle exec rake test # Run tests with coverage report
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
### The `include Resteze` pattern
|
|
23
|
+
|
|
24
|
+
When a module does `include Resteze`, the `included` block in `lib/resteze.rb` fires and sets up a full set of namespaced constants inside the consuming module:
|
|
25
|
+
|
|
26
|
+
- `MyApi::Object` — base Hashie::Trash subclass for all resource objects
|
|
27
|
+
- `MyApi::Client` — Faraday-based HTTP client (thread-safe via `Thread.current`)
|
|
28
|
+
- `MyApi::ApiResource` — extends Object with `retrieve`, `resource_path`, `refresh`
|
|
29
|
+
- `MyApi::ListObject` — Hashie::Array subclass for paginated list responses
|
|
30
|
+
- `MyApi::Middleware::RaiseError` — Faraday middleware for HTTP error handling
|
|
31
|
+
- `MyApi::List`, `MyApi::Save` — mixins consumers include on specific resources
|
|
32
|
+
- `MyApi::Error` and all subclasses — namespaced error hierarchy
|
|
33
|
+
|
|
34
|
+
This means each consuming gem gets its own isolated class hierarchy; errors from one API won't be caught by rescue clauses for another.
|
|
35
|
+
|
|
36
|
+
### `ApiModule` — the ancestry resolver
|
|
37
|
+
|
|
38
|
+
`Resteze::ApiModule` is mixed into every class in the hierarchy. Its `api_module` class method walks the constant name ancestry (`Widget` → `MyApi::Widget` → `MyApi`) to find the module that `include`d Resteze. This is what allows `MyApi::Widget.request(...)` to automatically use `MyApi::Client` rather than needing any explicit wiring.
|
|
39
|
+
|
|
40
|
+
### Request flow
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
MyApi::Widget.retrieve(id)
|
|
44
|
+
→ ApiResource#refresh
|
|
45
|
+
→ Request.request(:get, path)
|
|
46
|
+
→ MyApi::Client.active_client.execute_request(method, path)
|
|
47
|
+
→ Faraday connection (thread-local default_client)
|
|
48
|
+
→ Middleware::RaiseError
|
|
49
|
+
→ Response.from_faraday_response
|
|
50
|
+
→ Object#initialize_from(resp.data)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
GET/HEAD/DELETE params become query strings; all other methods send a JSON body.
|
|
54
|
+
|
|
55
|
+
### Object / property system
|
|
56
|
+
|
|
57
|
+
`Resteze::Object` extends `Hashie::Trash`, which provides typed `property` declarations with optional transforms, defaults, and translations (key remapping). Unknown keys that don't match a declared property are stored in `@property_bag` rather than raising, allowing forward compatibility with API changes.
|
|
58
|
+
|
|
59
|
+
`object_key` (default: `nil`) lets a resource unwrap a top-level envelope key from API responses. `list_key` (default: `:data`) tells `ListObject` which key holds the array of items.
|
|
60
|
+
|
|
61
|
+
### Mixins: List and Save
|
|
62
|
+
|
|
63
|
+
- **`Resteze::List`** adds a class-level `.list(params:)` that issues a GET to `resource_path` and constructs a `ListObject`.
|
|
64
|
+
- **`Resteze::Save`** adds `#save` which issues POST (new) or PUT (persisted) based on `persisted?` (presence of `id`).
|
|
65
|
+
|
|
66
|
+
Both are opt-in; include them on a resource class when needed.
|
|
67
|
+
|
|
68
|
+
### Testing helpers
|
|
69
|
+
|
|
70
|
+
`lib/resteze/testing/` provides helpers for consumers testing their own gem:
|
|
71
|
+
- `Resteze::Testing::Minitest` — `has_property` assertion helper and `assert_config_property`
|
|
72
|
+
- `Resteze::Testing::RSpec` — equivalent helpers for RSpec
|
|
73
|
+
|
|
74
|
+
The gem's own tests use **Minitest** with **WebMock** (net connections disabled globally). The test helper defines `AcmeApi` as a reference implementation of a consuming module.
|
data/README.md
CHANGED
|
@@ -78,6 +78,37 @@ end
|
|
|
78
78
|
|
|
79
79
|
You can define additional resources, customize paths, and add methods as needed. Resteze handles requests, responses, and error management for you, so you can focus on your API's business logic.
|
|
80
80
|
|
|
81
|
+
### Instrumentation
|
|
82
|
+
|
|
83
|
+
Resteze fires an `ActiveSupport::Notifications` event for every HTTP request, making it easy to track performance metrics in host applications.
|
|
84
|
+
|
|
85
|
+
The event name is `request.<api_module_key>`, where the key is derived from your module name (e.g. `MyCoolApi` → `"request.my_cool_api"`).
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
ActiveSupport::Notifications.subscribe("request.my_cool_api") do |event|
|
|
89
|
+
event.duration # elapsed time in milliseconds
|
|
90
|
+
event.payload[:method] # :get, :post, :put, etc.
|
|
91
|
+
event.payload[:path] # "/widgets/123"
|
|
92
|
+
event.payload[:status] # 200, 404, etc.
|
|
93
|
+
event.payload[:request_id] # value of the Request-Id response header
|
|
94
|
+
event.payload[:api_module] # "MyCoolApi"
|
|
95
|
+
event.payload[:exception] # [ExceptionClass, message] if the request raised
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The event fires on every request — including those that raise errors — so you can feed `event.duration` directly into a histogram for p95 and other percentile calculations. Because `ActiveSupport::Notifications` short-circuits when there are no subscribers, there is no overhead when instrumentation is not in use.
|
|
100
|
+
|
|
101
|
+
To override the event name key for a module:
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
module MyCoolApi
|
|
105
|
+
include Resteze
|
|
106
|
+
|
|
107
|
+
INSTRUMENTATION_KEY = "cool_api"
|
|
108
|
+
end
|
|
109
|
+
# => subscribes to "request.cool_api"
|
|
110
|
+
```
|
|
111
|
+
|
|
81
112
|
## Contributing
|
|
82
113
|
|
|
83
114
|
Bug reports and pull requests are welcome on GitHub at https://github.com/rwx-services/resteze.
|