Class: Steppe::Service

Inherits:
Object
  • Object
show all
Defined in:
lib/steppe/service.rb

Defined Under Namespace

Classes: OpenAPISerializer, Server, Tag

Constant Summary collapse

VERBS =
i[get post put patch delete].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize {|_self| ... } ⇒ Service

Returns a new instance of Service.

Yields:

  • (_self)

Yield Parameters:



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/steppe/service.rb', line 26

def initialize(&)
  @lookup = {}
  @title = ''
  @description = ''
  @version = '0.0.1'
  @node_name = :service
  @servers = []
  @tags = []
  @security_schemes = {}
  @registered_security_schemes = {}
  yield self if block_given?
  freeze
end

Instance Attribute Details

#descriptionObject

Returns the value of attribute description.



24
25
26
# File 'lib/steppe/service.rb', line 24

def description
  @description
end

#node_nameObject (readonly)

Returns the value of attribute node_name.



23
24
25
# File 'lib/steppe/service.rb', line 23

def node_name
  @node_name
end

#registered_security_schemesObject (readonly)

Returns the value of attribute registered_security_schemes.



23
24
25
# File 'lib/steppe/service.rb', line 23

def registered_security_schemes
  @registered_security_schemes
end

#security_schemesObject (readonly)

Returns the value of attribute security_schemes.



23
24
25
# File 'lib/steppe/service.rb', line 23

def security_schemes
  @security_schemes
end

#serversObject (readonly)

Returns the value of attribute servers.



23
24
25
# File 'lib/steppe/service.rb', line 23

def servers
  @servers
end

#tagsObject (readonly)

Returns the value of attribute tags.



23
24
25
# File 'lib/steppe/service.rb', line 23

def tags
  @tags
end

#titleObject

Returns the value of attribute title.



24
25
26
# File 'lib/steppe/service.rb', line 24

def title
  @title
end

#versionObject

Returns the value of attribute version.



24
25
26
# File 'lib/steppe/service.rb', line 24

def version
  @version
end

Instance Method Details

#[](name) ⇒ Object



40
# File 'lib/steppe/service.rb', line 40

def [](name) = @lookup[name]

#basic_auth(name, store: {}) ⇒ self

Register a Basic HTTP authentication security scheme. This is a convenience method that creates a Basic auth scheme and registers it.

Examples:

Basic usage with hash store

service.basic_auth 'BasicAuth', store: {
  'admin' => 'secret123',
  'user' => 'password456'
}

With custom credentials store

class DatabaseCredentialsStore
  def lookup(username)
    user = User.find_by(username: username)
    user&.password_digest
  end
end

service.basic_auth 'BasicAuth', store: DatabaseCredentialsStore.new

Using in an endpoint

service.basic_auth 'BasicAuth', store: { 'admin' => 'secret' }
service.get :protected, '/protected' do |e|
  e.security 'BasicAuth'
  # ... endpoint definition
end

Parameters:

  • name (String)

    The security scheme name (used to reference in endpoints)

  • store (Hash, Auth::Basic::CredentialsStoreInterface) (defaults to: {})

    Credentials store mapping usernames to passwords. Can be a Hash (converted to SimpleUserPasswordStore) or a custom store implementing the CredentialsStoreInterface.

Returns:

  • (self)

See Also:



110
111
112
# File 'lib/steppe/service.rb', line 110

def basic_auth(name, store: {})
  security_scheme Auth::Basic.new(name, store:)
end

#bearer_auth(name, store: {}, format: 'string') ⇒ self

Register a Bearer token authentication security scheme. This is a convenience method that creates a Bearer auth scheme and registers it.

Examples:

Basic usage with hash store

service.bearer_auth 'api_key', store: {
  'token123' => ['read:users', 'write:users'],
  'token456' => ['read:posts']
}

With JWT format hint

service.bearer_auth 'jwt_auth', store: my_token_store, format: 'JWT'

Parameters:

  • name (String)

    The security scheme name (used to reference in endpoints)

  • store (Hash, Auth::TokenStoreInterface) (defaults to: {})

    Token store mapping tokens to scopes. Can be a Hash (converted to HashTokenStore) or a custom store implementing the TokenStoreInterface.

  • format (String) (defaults to: 'string')

    Bearer token format hint for documentation (e.g., ‘JWT’, ‘opaque’)

Returns:

  • (self)

    Returns self for method chaining

See Also:



73
74
75
# File 'lib/steppe/service.rb', line 73

def bearer_auth(name, store: {}, format: 'string')
  security_scheme Auth::Bearer.new(name, store:, format:)
end

#endpointsObject



41
# File 'lib/steppe/service.rb', line 41

def endpoints = @lookup.values

#route_with(router) ⇒ Object

Registers all defined endpoints with the given router. The router is expected to respond to HTTP verb methods (e.g., get, post). ie. router.get ‘/users/:id’, to: rack_endpoint

Examples:

app = MyService.route_with(Hanami::Router.new)
run app
app = Hanami::Router.new do
  scope '/api' do
    MyService.route_with(self)
  end
end

Parameters:

  • router (Object)

    A router instance that responds to HTTP verb methods (e.g., get, post).

Returns:

  • (Object)

    The router with registered endpoints.



218
219
220
221
222
223
# File 'lib/steppe/service.rb', line 218

def route_with(router)
  endpoints.each do |endpoint|
    router.public_send(endpoint.verb, endpoint.path.to_s, to: endpoint.to_rack)
  end
  router
end

#security(scheme_name, scopes = []) ⇒ self

Apply a security requirement globally to endpoints defined after this call. This registers a security scheme with required scopes at the service level, making it apply to all endpoints defined after this method is called.

IMPORTANT: Order matters! This method only applies security to endpoints defined AFTER it is called, not to endpoints defined before.

Examples:

Apply Bearer auth globally to all endpoints defined after

service.bearer_auth 'api_key', store: {
  'token123' => ['read:users', 'write:users']
}
service.security 'api_key', ['read:users']
# All endpoints defined below will require this security

Order matters - security only applies to endpoints after the call

service.bearer_auth 'api_key', store: tokens
service.get :public_endpoint, '/public' { }  # No security required
service.security 'api_key', ['read:users']
service.get :protected_endpoint, '/protected' { }  # Security required

Multiple security schemes

service.bearer_auth 'api_key', store: tokens
service.bearer_auth 'admin_key', store: admin_tokens
service.security 'api_key', ['read:users']
service.security 'admin_key', ['admin']

Parameters:

  • scheme_name (String)

    The name of a registered security scheme

  • scopes (Array<String>) (defaults to: [])

    Required scopes for this security requirement

Returns:

  • (self)

    Returns self for method chaining

Raises:

  • (KeyError)

    If the security scheme has not been registered

See Also:



172
173
174
175
176
# File 'lib/steppe/service.rb', line 172

def security(scheme_name, scopes = [])
  scheme = security_schemes.fetch(scheme_name)
  @registered_security_schemes[scheme_name] = scopes
  self
end

#security_scheme(scheme) ⇒ self

Register a security scheme for use in endpoints. Security schemes define authentication methods that can be applied to endpoints.

Examples:

Register a custom security scheme

bearer = Steppe::Auth::Bearer.new('my_auth', store: token_store)
service.security_scheme(bearer)

Register and use in an endpoint

service.bearer_auth 'api_key', store: { 'token123' => ['read:users'] }
service.get :users, '/users' do |e|
  e.security 'api_key', ['read:users']
  # ... endpoint definition
end

Parameters:

Returns:

  • (self)

    Returns self for method chaining

See Also:



133
134
135
136
137
# File 'lib/steppe/service.rb', line 133

def security_scheme(scheme)
  scheme => Auth::SecuritySchemeInterface
  @security_schemes[scheme.name] = scheme
  self
end

#server(args = {}) ⇒ Object



43
44
45
46
# File 'lib/steppe/service.rb', line 43

def server(args = {})
  @servers << Server.parse(args)
  self
end

#specs(path = '/') ⇒ Object

Generates an endpoint that serves the OpenAPI specification in JSON format.

Parameters:

  • path (String) (defaults to: '/')

    The path where the OpenAPI spec will be available (default: ‘/’)



195
196
197
198
199
200
# File 'lib/steppe/service.rb', line 195

def specs(path = '/')
  get :__open_api, path do |e|
    e.no_spec!
    e.json 200..299, OpenAPISerializer.new(self)
  end
end

#tag(name, description: nil, external_docs: nil) ⇒ Object



48
49
50
51
# File 'lib/steppe/service.rb', line 48

def tag(name, description: nil, external_docs: nil)
  @tags << Tag.parse(name:, description:, external_docs:)
  self
end