w3c_api 0.1.2 → 0.1.4

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.
data/lib/w3c_api/hal.rb CHANGED
@@ -1,16 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'singleton'
4
+ require 'lutaml/hal'
4
5
  require_relative 'models'
5
6
 
6
7
  module W3cApi
8
+ # Simple parameter class to satisfy lutaml-hal validation requirements
9
+ class SimpleParameter
10
+ attr_reader :name, :location, :required, :default_value
11
+
12
+ def initialize(name, location: :path, required: false, default_value: nil)
13
+ @name = name.to_s
14
+ @location = location
15
+ @required = required
16
+ @default_value = default_value
17
+ end
18
+
19
+ def validate!
20
+ # Simple validation - just ensure name is present
21
+ raise ArgumentError, 'Parameter name cannot be empty' if @name.nil? || @name.empty?
22
+ end
23
+
24
+ def path_parameter?
25
+ @location == :path
26
+ end
27
+
28
+ def query_parameter?
29
+ @location == :query
30
+ end
31
+
32
+ def validate_value(value)
33
+ # Simple validation - accept any non-nil value
34
+ !value.nil?
35
+ end
36
+ end
37
+
7
38
  class Hal
8
39
  include Singleton
9
40
 
10
41
  API_URL = 'https://api.w3.org/'
11
42
 
12
43
  def initialize
13
- setup
44
+ # Don't call setup here - it will be called when register is first accessed
14
45
  end
15
46
 
16
47
  def client
@@ -21,242 +52,313 @@ module W3cApi
21
52
  return @register if @register
22
53
 
23
54
  @register = Lutaml::Hal::ModelRegister.new(name: :w3c_api, client: client)
24
- Lutaml::Hal::GlobalRegister.instance.register(
25
- :w3c_api, @register
26
- )
55
+ Lutaml::Hal::GlobalRegister.instance.register(:w3c_api, @register)
56
+
57
+ # Re-run setup to register all endpoints with the new register
58
+ setup
59
+
27
60
  @register
28
61
  end
29
62
 
63
+ def reset_register
64
+ @register = nil
65
+ end
66
+
30
67
  private
31
68
 
32
- # Common pagination query parameters
33
- PAGINATION_PARAMS = { 'page' => '{page}',
34
- 'items' => '{items}' }.freeze
69
+ # Common pagination parameters (simplified without EndpointParameter)
70
+ def pagination_parameters
71
+ [
72
+ SimpleParameter.new('page', location: :query),
73
+ SimpleParameter.new('items', location: :query)
74
+ ]
75
+ end
76
+
77
+ # Parameters for endpoints with embed support (simplified without EndpointParameter)
78
+ def embed_parameters
79
+ [
80
+ SimpleParameter.new('embed', location: :query)
81
+ ] + pagination_parameters
82
+ end
83
+
84
+ # Helper methods for common parameter types (using SimpleParameter)
85
+ def string_path_param(name, _description = nil)
86
+ SimpleParameter.new(name, location: :path)
87
+ end
88
+
89
+ def integer_path_param(name, _description = nil)
90
+ SimpleParameter.new(name, location: :path)
91
+ end
92
+
93
+ def string_query_param(name, _description = nil, required: false)
94
+ SimpleParameter.new(name, location: :query, required: required)
95
+ end
35
96
 
36
97
  # Helper method to add index endpoints with pagination
37
- def add_index_endpoint(id, url, model, query_params = PAGINATION_PARAMS)
98
+ def add_index_endpoint(id, url, model, parameters = pagination_parameters)
38
99
  register.add_endpoint(
39
100
  id: id,
40
101
  type: :index,
41
102
  url: url,
42
103
  model: model,
43
- query_params: query_params
104
+ parameters: parameters
44
105
  )
45
106
  end
46
107
 
47
108
  # Helper method to add resource endpoints
48
- def add_resource_endpoint(id, url, model)
49
- register.add_endpoint(id: id, type: :resource, url: url, model: model)
109
+ def add_resource_endpoint(id, url, model, parameters = [])
110
+ register.add_endpoint(
111
+ id: id,
112
+ type: :resource,
113
+ url: url,
114
+ model: model,
115
+ parameters: parameters
116
+ )
50
117
  end
51
118
 
52
- # Helper method to add nested index endpoints for a parent resource
53
- def add_nested_index_endpoints(parent, parent_id_param, nested_configs)
54
- nested_configs.each do |config|
55
- # Convert plural parent to singular for endpoint naming
56
- singular_parent = parent.end_with?('s') ? parent[0..-2] : parent
57
- id = "#{singular_parent}_#{config[:name]}_index".to_sym
58
- url = "/#{parent}/#{parent_id_param}/#{config[:path]}"
59
- add_index_endpoint(id, url, config[:model])
60
- end
119
+ # Helper method to add endpoints with path parameters
120
+ def add_endpoint_with_path_params(id, type, url, model, path_params = [], query_params = [])
121
+ parameters = (path_params + query_params).compact
122
+ register.add_endpoint(
123
+ id: id,
124
+ type: type,
125
+ url: url,
126
+ model: model,
127
+ parameters: parameters
128
+ )
61
129
  end
62
130
 
63
131
  def setup
64
- # Affiliation endpoints
65
- add_index_endpoint(
66
- :affiliation_index,
67
- '/affiliations',
68
- Models::AffiliationIndex
69
- )
70
- add_resource_endpoint(
71
- :affiliation_resource,
72
- '/affiliations/{id}',
73
- Models::Affiliation
74
- )
75
- add_index_endpoint(
76
- :affiliation_participants_index,
77
- '/affiliations/{id}/participants',
78
- Models::ParticipantIndex
79
- )
132
+ # Specification endpoints with embed support
80
133
  add_index_endpoint(
81
- :affiliation_participations_index,
82
- '/affiliations/{id}/participations',
83
- Models::ParticipationIndex
134
+ :specification_index,
135
+ '/specifications',
136
+ Models::SpecificationIndex,
137
+ embed_parameters
84
138
  )
85
139
 
86
- # register.add_endpoint(
87
- # id: :charter_resource,
88
- # type: :resource,
89
- # url: '/charters/{id}',
90
- # model: Models::Charter
91
- # )
92
-
93
- # Ecosystem endpoints
94
- add_index_endpoint(
95
- :ecosystem_index,
96
- '/ecosystems',
97
- Models::EcosystemIndex
98
- )
99
- add_resource_endpoint(
100
- :ecosystem_resource,
101
- '/ecosystems/{id}',
102
- Models::Ecosystem
140
+ # Specification by status endpoint
141
+ add_endpoint_with_path_params(
142
+ :specification_by_status_index,
143
+ :index,
144
+ '/specifications',
145
+ Models::SpecificationIndex,
146
+ [],
147
+ [string_query_param('status', required: true)] + pagination_parameters
103
148
  )
104
- add_index_endpoint(
105
- :ecosystem_evangelists_index,
106
- '/ecosystems/{shortname}/evangelists',
107
- Models::EvangelistIndex
149
+ add_endpoint_with_path_params(
150
+ :specification_resource,
151
+ :resource,
152
+ '/specifications/{shortname}',
153
+ Models::Specification,
154
+ [string_path_param('shortname')]
108
155
  )
109
- add_index_endpoint(
110
- :ecosystem_groups_index,
111
- '/ecosystems/{shortname}/groups',
112
- Models::GroupIndex
156
+
157
+ # Specification version endpoints
158
+ add_endpoint_with_path_params(
159
+ :specification_resource_version_index,
160
+ :index,
161
+ '/specifications/{shortname}/versions',
162
+ Models::SpecVersionIndex,
163
+ [string_path_param('shortname')],
164
+ pagination_parameters
113
165
  )
114
- add_index_endpoint(
115
- :ecosystem_member_organizations_index,
116
- '/ecosystems/{shortname}/member-organizations',
117
- Models::AffiliationIndex
166
+ add_endpoint_with_path_params(
167
+ :specification_resource_version_resource,
168
+ :resource,
169
+ '/specifications/{shortname}/versions/{version}',
170
+ Models::SpecVersion,
171
+ [
172
+ string_path_param('shortname'),
173
+ string_path_param('version')
174
+ ]
118
175
  )
119
176
 
120
- # Group endpoints
121
- add_index_endpoint(
122
- :group_index,
123
- '/groups',
124
- Models::GroupIndex
177
+ # Specification version editors and deliverers
178
+ add_endpoint_with_path_params(
179
+ :specification_version_editors_index,
180
+ :index,
181
+ '/specifications/{shortname}/versions/{version}/editors',
182
+ Models::EditorIndex,
183
+ [
184
+ string_path_param('shortname'),
185
+ string_path_param('version')
186
+ ],
187
+ pagination_parameters
188
+ )
189
+ add_endpoint_with_path_params(
190
+ :specification_version_deliverers_index,
191
+ :index,
192
+ '/specifications/{shortname}/versions/{version}/deliverers',
193
+ Models::DelivererIndex,
194
+ [
195
+ string_path_param('shortname'),
196
+ string_path_param('version')
197
+ ],
198
+ pagination_parameters
125
199
  )
126
- add_resource_endpoint(
127
- :group_resource,
128
- '/groups/{id}',
129
- Models::Group
130
- )
131
- add_nested_index_endpoints(
132
- 'groups',
133
- '{id}', [
134
- { name: 'specifications', path: 'specifications',
135
- model: Models::SpecificationIndex },
136
- { name: 'charters', path: 'charters',
137
- model: Models::CharterIndex },
138
- { name: 'users', path: 'users',
139
- model: Models::UserIndex },
140
- { name: 'chairs', path: 'chairs',
141
- model: Models::ChairIndex },
142
- { name: 'team_contacts', path: 'teamcontacts',
143
- model: Models::TeamContactIndex },
144
- { name: 'participations', path: 'participations',
145
- model: Models::ParticipationIndex }
146
- ]
200
+
201
+ # Specification version predecessors and successors
202
+ add_endpoint_with_path_params(
203
+ :specification_version_predecessors_index,
204
+ :index,
205
+ '/specifications/{shortname}/versions/{version}/predecessors',
206
+ Models::SpecVersionPredecessorIndex,
207
+ [
208
+ string_path_param('shortname'),
209
+ string_path_param('version')
210
+ ],
211
+ pagination_parameters
212
+ )
213
+ add_endpoint_with_path_params(
214
+ :specification_version_successors_index,
215
+ :index,
216
+ '/specifications/{shortname}/versions/{version}/successors',
217
+ Models::SpecVersionSuccessorIndex,
218
+ [
219
+ string_path_param('shortname'),
220
+ string_path_param('version')
221
+ ],
222
+ pagination_parameters
147
223
  )
148
224
 
149
- # Participation endpoints
225
+ # Specification related endpoints
226
+ %w[supersedes superseded_by editors deliverers].each do |relation|
227
+ add_endpoint_with_path_params(
228
+ :"specification_#{relation}_index",
229
+ :index,
230
+ "/specifications/{shortname}/#{relation.tr('_', '-')}",
231
+ relation.include?('editor') ? Models::UserIndex : Models::GroupIndex,
232
+ [string_path_param('shortname')],
233
+ pagination_parameters
234
+ )
235
+ end
236
+
237
+ # TODO: Why is this endpoint needed? There already is /specifications/{shortname}...
150
238
  # register.add_endpoint(
151
- # id: :participation_index,
239
+ # id: :specification_by_shortname_index,
152
240
  # type: :index,
153
- # url: '/participations',
154
- # model: Models::ParticipationIndex
241
+ # url: '/specifications-by-shortname/{shortname}',
242
+ # model: Models::SpecificationIndex
155
243
  # )
156
244
 
157
- add_resource_endpoint(
158
- :participation_resource,
159
- '/participations/{id}',
160
- Models::Participation
161
- )
162
- add_index_endpoint(
163
- :participation_participants_index,
164
- '/participations/{id}/participants',
165
- Models::ParticipantIndex
166
- )
167
-
168
- # Serie endpoints
245
+ # Series endpoints with embed support
169
246
  add_index_endpoint(
170
247
  :serie_index,
171
248
  '/specification-series',
172
- Models::SerieIndex
249
+ Models::SerieIndex,
250
+ embed_parameters
173
251
  )
174
- add_resource_endpoint(
252
+ add_endpoint_with_path_params(
175
253
  :serie_resource,
254
+ :resource,
176
255
  '/specification-series/{shortname}',
177
- Models::Serie
256
+ Models::Serie,
257
+ [string_path_param('shortname')]
178
258
  )
179
- add_index_endpoint(
259
+ add_endpoint_with_path_params(
180
260
  :serie_specification_resource,
261
+ :index,
181
262
  '/specification-series/{shortname}/specifications',
182
- Models::SpecificationIndex
263
+ Models::SpecificationIndex,
264
+ [string_path_param('shortname')],
265
+ pagination_parameters
183
266
  )
184
267
 
185
- # Specification endpoints
186
- add_index_endpoint(
187
- :specification_index,
188
- '/specifications',
189
- Models::SpecificationIndex
190
- )
191
- add_resource_endpoint(
192
- :specification_resource,
193
- '/specifications/{shortname}',
194
- Models::Specification
195
- )
196
- add_index_endpoint(
197
- :specification_resource_version_index,
198
- '/specifications/{shortname}/versions',
199
- Models::SpecVersionIndex
200
- )
201
- add_resource_endpoint(
202
- :specification_resource_version_resource,
203
- '/specifications/{shortname}/versions/{version}',
204
- Models::SpecVersion
205
- )
268
+ # Group endpoints with embed support
206
269
  add_index_endpoint(
207
- :specification_version_predecessors_index,
208
- '/specifications/{shortname}/versions/{version}/predecessors',
209
- Models::SpecVersionIndex
210
- )
211
- add_index_endpoint(
212
- :specification_version_successors_index,
213
- '/specifications/{shortname}/versions/{version}/successors',
214
- Models::SpecVersionIndex
215
- )
216
- add_index_endpoint(
217
- :specification_by_status_index,
218
- '/specifications-by-status/{status}',
219
- Models::SpecificationIndex
220
- )
221
- add_index_endpoint(
222
- :specification_supersedes_index,
223
- '/specifications/{shortname}/supersedes',
224
- Models::SpecificationIndex
225
- )
226
- add_index_endpoint(
227
- :specification_superseded_by_index,
228
- '/specifications/{shortname}/superseded',
229
- Models::SpecificationIndex
270
+ :group_index,
271
+ '/groups',
272
+ Models::GroupIndex,
273
+ embed_parameters
230
274
  )
231
- add_index_endpoint(
232
- :specification_version_editors_index,
233
- '/specifications/{shortname}/version/{version}/editors',
234
- Models::UserIndex
275
+ add_endpoint_with_path_params(
276
+ :group_resource,
277
+ :resource,
278
+ '/groups/{id}',
279
+ Models::Group,
280
+ [integer_path_param('id')]
281
+ )
282
+ add_endpoint_with_path_params(
283
+ :group_by_type_shortname_resource,
284
+ :resource,
285
+ '/groups/{type}/{shortname}',
286
+ Models::Group,
287
+ [
288
+ string_path_param('type'),
289
+ string_path_param('shortname')
290
+ ]
235
291
  )
236
- add_index_endpoint(
237
- :specification_version_deliverers_index,
238
- '/specifications/{shortname}/version/{version}/deliverers',
239
- Models::UserIndex
292
+ add_endpoint_with_path_params(
293
+ :group_by_type_index,
294
+ :index,
295
+ '/groups/{type}',
296
+ Models::GroupIndex,
297
+ [string_path_param('type')],
298
+ pagination_parameters
299
+ )
300
+ # Group nested endpoints
301
+ add_endpoint_with_path_params(
302
+ :group_specifications_index,
303
+ :index,
304
+ '/groups/{id}/specifications',
305
+ Models::SpecificationIndex,
306
+ [integer_path_param('id')],
307
+ pagination_parameters
308
+ )
309
+ add_endpoint_with_path_params(
310
+ :group_users_index,
311
+ :index,
312
+ '/groups/{id}/users',
313
+ Models::UserIndex,
314
+ [integer_path_param('id')],
315
+ pagination_parameters
316
+ )
317
+ add_endpoint_with_path_params(
318
+ :group_charters_index,
319
+ :index,
320
+ '/groups/{id}/charters',
321
+ Models::CharterIndex,
322
+ [integer_path_param('id')],
323
+ pagination_parameters
324
+ )
325
+ add_endpoint_with_path_params(
326
+ :group_chairs_index,
327
+ :index,
328
+ '/groups/{id}/chairs',
329
+ Models::ChairIndex,
330
+ [integer_path_param('id')],
331
+ pagination_parameters
332
+ )
333
+ add_endpoint_with_path_params(
334
+ :group_team_contacts_index,
335
+ :index,
336
+ '/groups/{id}/teamcontacts',
337
+ Models::TeamContactIndex,
338
+ [integer_path_param('id')],
339
+ pagination_parameters
340
+ )
341
+ add_endpoint_with_path_params(
342
+ :group_participations_index,
343
+ :index,
344
+ '/groups/{id}/participations',
345
+ Models::ParticipationIndex,
346
+ [integer_path_param('id')],
347
+ pagination_parameters
240
348
  )
241
349
 
242
- # TODO: Why is this endpoint needed? There already is /specifications/{shortname}...
243
- # register.add_endpoint(
244
- # id: :specification_by_shortname_index,
245
- # type: :index,
246
- # url: '/specifications-by-shortname/{shortname}',
247
- # model: Models::SpecificationIndex
248
- # )
249
-
250
350
  # Translation endpoints
251
351
  add_index_endpoint(
252
352
  :translation_index,
253
353
  '/translations',
254
354
  Models::TranslationIndex
255
355
  )
256
- add_resource_endpoint(
356
+ add_endpoint_with_path_params(
257
357
  :translation_resource,
358
+ :resource,
258
359
  '/translations/{id}',
259
- Models::Translation
360
+ Models::Translation,
361
+ [integer_path_param('id')]
260
362
  )
261
363
 
262
364
  # User endpoints
@@ -267,27 +369,151 @@ module W3cApi
267
369
  # url: '/users',
268
370
  # model: Models::UserIndex
269
371
  # )
270
- add_resource_endpoint(
372
+ add_endpoint_with_path_params(
271
373
  :user_resource,
374
+ :resource,
272
375
  '/users/{hash}',
273
- Models::User
274
- )
275
- add_nested_index_endpoints(
276
- 'users',
277
- '{hash}', [
278
- { name: 'groups', path: 'groups',
279
- model: Models::GroupIndex },
280
- { name: 'affiliations', path: 'affiliations',
281
- model: Models::AffiliationIndex },
282
- { name: 'participations', path: 'participations',
283
- model: Models::ParticipationIndex },
284
- { name: 'chair_of_groups', path: 'chair-of-groups',
285
- model: Models::GroupIndex },
286
- { name: 'team_contact_of_groups', path: 'team-contact-of-groups',
287
- model: Models::GroupIndex },
288
- { name: 'specifications', path: 'specifications',
289
- model: Models::SpecificationIndex }
290
- ]
376
+ Models::User,
377
+ [string_path_param('hash')]
378
+ )
379
+
380
+ # User nested endpoints
381
+ add_endpoint_with_path_params(
382
+ :user_groups_index,
383
+ :index,
384
+ '/users/{hash}/groups',
385
+ Models::GroupIndex,
386
+ [string_path_param('hash')],
387
+ pagination_parameters
388
+ )
389
+ add_endpoint_with_path_params(
390
+ :user_affiliations_index,
391
+ :index,
392
+ '/users/{hash}/affiliations',
393
+ Models::AffiliationIndex,
394
+ [string_path_param('hash')],
395
+ pagination_parameters
396
+ )
397
+ add_endpoint_with_path_params(
398
+ :user_participations_index,
399
+ :index,
400
+ '/users/{hash}/participations',
401
+ Models::ParticipationIndex,
402
+ [string_path_param('hash')],
403
+ pagination_parameters
404
+ )
405
+ add_endpoint_with_path_params(
406
+ :user_chair_of_groups_index,
407
+ :index,
408
+ '/users/{hash}/chair-of-groups',
409
+ Models::GroupIndex,
410
+ [string_path_param('hash')],
411
+ pagination_parameters
412
+ )
413
+ add_endpoint_with_path_params(
414
+ :user_team_contact_of_groups_index,
415
+ :index,
416
+ '/users/{hash}/team-contact-of-groups',
417
+ Models::GroupIndex,
418
+ [string_path_param('hash')],
419
+ pagination_parameters
420
+ )
421
+ add_endpoint_with_path_params(
422
+ :user_specifications_index,
423
+ :index,
424
+ '/users/{hash}/specifications',
425
+ Models::SpecificationIndex,
426
+ [string_path_param('hash')],
427
+ pagination_parameters
428
+ )
429
+
430
+ # Affiliation endpoints
431
+ add_index_endpoint(
432
+ :affiliation_index,
433
+ '/affiliations',
434
+ Models::AffiliationIndex
435
+ )
436
+ add_endpoint_with_path_params(
437
+ :affiliation_resource,
438
+ :resource,
439
+ '/affiliations/{id}',
440
+ Models::Affiliation,
441
+ [integer_path_param('id')]
442
+ )
443
+
444
+ # Affiliation nested endpoints
445
+ add_endpoint_with_path_params(
446
+ :affiliation_participants_index,
447
+ :index,
448
+ '/affiliations/{id}/participants',
449
+ Models::ParticipantIndex,
450
+ [integer_path_param('id')],
451
+ pagination_parameters
452
+ )
453
+ add_endpoint_with_path_params(
454
+ :affiliation_participations_index,
455
+ :index,
456
+ '/affiliations/{id}/participations',
457
+ Models::ParticipationIndex,
458
+ [integer_path_param('id')],
459
+ pagination_parameters
460
+ )
461
+
462
+ # Ecosystem endpoints
463
+ add_index_endpoint(
464
+ :ecosystem_index,
465
+ '/ecosystems',
466
+ Models::EcosystemIndex
467
+ )
468
+ add_endpoint_with_path_params(
469
+ :ecosystem_resource,
470
+ :resource,
471
+ '/ecosystems/{shortname}',
472
+ Models::Ecosystem,
473
+ [string_path_param('shortname')]
474
+ )
475
+
476
+ # Ecosystem nested endpoints
477
+ add_endpoint_with_path_params(
478
+ :ecosystem_groups_index,
479
+ :index,
480
+ '/ecosystems/{shortname}/groups',
481
+ Models::GroupIndex,
482
+ [string_path_param('shortname')],
483
+ pagination_parameters
484
+ )
485
+ add_endpoint_with_path_params(
486
+ :ecosystem_evangelists_index,
487
+ :index,
488
+ '/ecosystems/{shortname}/evangelists',
489
+ Models::EvangelistIndex,
490
+ [string_path_param('shortname')],
491
+ pagination_parameters
492
+ )
493
+ add_endpoint_with_path_params(
494
+ :ecosystem_member_organizations_index,
495
+ :index,
496
+ '/ecosystems/{shortname}/member-organizations',
497
+ Models::AffiliationIndex,
498
+ [string_path_param('shortname')],
499
+ pagination_parameters
500
+ )
501
+
502
+ # Participation endpoints
503
+ add_endpoint_with_path_params(
504
+ :participation_resource,
505
+ :resource,
506
+ '/participations/{id}',
507
+ Models::Participation,
508
+ [integer_path_param('id')]
509
+ )
510
+ add_endpoint_with_path_params(
511
+ :participation_participants_index,
512
+ :index,
513
+ '/participations/{id}/participants',
514
+ Models::ParticipantIndex,
515
+ [integer_path_param('id')],
516
+ pagination_parameters
291
517
  )
292
518
  end
293
519
  end