resteze 0.3.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: da5b0f1ce7cd3e8c2677b9fe22f2c67b755475ea464b25821fc71f4054629bb6
4
- data.tar.gz: f8a4c6fa0bd2a169b7f8e818dacb14b11a0e6c69bebe49a6b77004a458351a9a
3
+ metadata.gz: 55dfa62b10235fa805a820a3c8a11fc01126141941c3dce30b54b62b484a2e18
4
+ data.tar.gz: 7b69653ef28303f319cb56b7bf94ff59cf09291aa3a9911d52158b71df026bb2
5
5
  SHA512:
6
- metadata.gz: 9c64c532a62d217fc2819c729fb684590ba0d29eb7ca2f83e9c1ee36a3b9db5e32bb2bc5ae082b3c94b6f0b783bc097b634e7668ad362c09cf1b150f7e607e55
7
- data.tar.gz: 6c5c871ed49367a69b401d32409200234352348ab305a0084b0aab8c61b22921115268dd32724c896d1b2eded83c3632e2d62c3ec8371437d5675b4a7fbc9e84
6
+ metadata.gz: ab516cd48e257b13bd1996e0bfd0f5c91a0fceb60e61c6883034f5ff898c560ce615a899f7759ef927e2a2dbd2652ec4d007eba05c235c0ba653b8b230b0a85c
7
+ data.tar.gz: df4fd41077a6555453a95d0786a05f378d1f466e78a47913d563605801d53c054741881e7da2c3dfc6923b23563d7fe8701fdd2d8c71aead5d269d74f7075cb1
data/CHANGELOG.md ADDED
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.3.1]
6
+
7
+ ### Added
8
+
9
+ - Minitest and RSpec testing helpers for resources and configuration.
10
+
11
+ ## [0.3.0]
12
+
13
+ ### Added
14
+
15
+ - Initial implementation of Resteze, a framework for building REST API client gems.
16
+ - Support for defining API resources, requests, and responses.
17
+ - Configuration management for API clients.
18
+ - Integration with Faraday, Hashie, and ActiveSupport.
19
+ - Middleware for error handling and request transformation.
20
+ - Serialization and deserialization of API responses.
21
+ - Thread-safe client management.
22
+ - Flexible resource paths and property mapping.
23
+
24
+ ## [0.1.0] - 2025-08-12
25
+
26
+ ### Added
27
+
28
+ - First public release.
29
+ - Documentation and usage examples.
30
+ - CI workflow for RuboCop and tests across Ruby 3.2–3.4.4.
31
+ - Code coverage reporting integration.
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
@@ -3,6 +3,8 @@
3
3
  </div>
4
4
 
5
5
  [![Continuous Integration](https://github.com/rwx-services/resteze/actions/workflows/ci.yml/badge.svg)](https://github.com/rwx-services/resteze/actions/workflows/ci.yml)
6
+ [![Gem Version](https://badge.fury.io/rb/resteze.svg)](https://badge.fury.io/rb/resteze)
7
+ [![Coverage Status](https://coveralls.io/repos/github/rwx-services/resteze/badge.svg?branch=main)](https://coveralls.io/github/rwx-services/resteze?branch=main)
6
8
 
7
9
  ---
8
10
 
@@ -76,6 +78,37 @@ end
76
78
 
77
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.
78
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
+
79
112
  ## Contributing
80
113
 
81
114
  Bug reports and pull requests are welcome on GitHub at https://github.com/rwx-services/resteze.