trailblazer-endpoint 0.0.3 → 0.0.8
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/.gitignore +16 -0
 - data/Appraisals +5 -0
 - data/CHANGES.md +27 -0
 - data/README.md +40 -5
 - data/Rakefile +7 -1
 - data/gemfiles/rails_app.gemfile +12 -0
 - data/lib/trailblazer/endpoint.rb +50 -14
 - data/lib/trailblazer/endpoint/adapter.rb +30 -121
 - data/lib/trailblazer/endpoint/builder.rb +1 -1
 - data/lib/trailblazer/endpoint/controller.rb +217 -1
 - data/lib/trailblazer/endpoint/dsl.rb +8 -3
 - data/lib/trailblazer/endpoint/options.rb +16 -69
 - data/lib/trailblazer/endpoint/protocol.rb +7 -11
 - data/lib/trailblazer/endpoint/protocol/cipher.rb +27 -0
 - data/lib/trailblazer/endpoint/protocol/controller.rb +102 -0
 - data/lib/trailblazer/endpoint/protocol/find_process_model.rb +15 -0
 - data/lib/trailblazer/endpoint/version.rb +1 -1
 - data/test/adapter/api_test.rb +6 -11
 - data/test/adapter/web_test.rb +2 -5
 - data/test/config_test.rb +25 -0
 - data/test/docs/controller_test.rb +220 -73
 - data/test/endpoint_test.rb +1 -1
 - data/test/rails-app/.gitignore +8 -2
 - data/test/rails-app/.ruby-version +1 -0
 - data/test/rails-app/Gemfile +21 -9
 - data/test/rails-app/Gemfile.lock +174 -118
 - data/test/rails-app/app/concepts/app/api/v1/representer/errors.rb +16 -0
 - data/test/rails-app/app/concepts/auth/jwt.rb +35 -0
 - data/test/rails-app/app/concepts/auth/operation/authenticate.rb +32 -0
 - data/test/rails-app/app/concepts/auth/operation/policy.rb +9 -0
 - data/test/rails-app/app/concepts/song/cell/create.rb +4 -0
 - data/test/rails-app/app/concepts/song/cell/new.rb +4 -0
 - data/test/rails-app/app/concepts/song/operation/create.rb +17 -0
 - data/test/rails-app/app/concepts/song/operation/show.rb +10 -0
 - data/test/rails-app/app/concepts/song/representer.rb +5 -0
 - data/test/rails-app/app/concepts/song/view/create.erb +1 -0
 - data/test/rails-app/app/concepts/song/view/new.erb +1 -0
 - data/test/rails-app/app/controllers/api/v1/songs_controller.rb +41 -0
 - data/test/rails-app/app/controllers/application_controller.rb +8 -1
 - data/test/rails-app/app/controllers/application_controller/api.rb +107 -0
 - data/test/rails-app/app/controllers/application_controller/web.rb +46 -0
 - data/test/rails-app/app/controllers/auth_controller.rb +44 -0
 - data/test/rails-app/app/controllers/home_controller.rb +5 -0
 - data/test/rails-app/app/controllers/songs_controller.rb +254 -13
 - data/test/rails-app/app/models/song.rb +6 -0
 - data/test/rails-app/app/models/user.rb +7 -0
 - data/test/rails-app/bin/bundle +114 -0
 - data/test/rails-app/bin/rails +4 -0
 - data/test/rails-app/bin/rake +4 -0
 - data/test/rails-app/bin/setup +33 -0
 - data/test/rails-app/config/application.rb +26 -3
 - data/test/rails-app/config/credentials.yml.enc +1 -0
 - data/test/rails-app/config/database.yml +2 -2
 - data/test/rails-app/config/environments/development.rb +7 -17
 - data/test/rails-app/config/environments/production.rb +28 -23
 - data/test/rails-app/config/environments/test.rb +10 -12
 - data/test/rails-app/config/initializers/application_controller_renderer.rb +6 -4
 - data/test/rails-app/config/initializers/cors.rb +16 -0
 - data/test/rails-app/config/initializers/trailblazer.rb +2 -0
 - data/test/rails-app/config/locales/en.yml +11 -1
 - data/test/rails-app/config/master.key +1 -0
 - data/test/rails-app/config/routes.rb +27 -4
 - data/test/rails-app/db/schema.rb +15 -0
 - data/test/rails-app/test/controllers/api_songs_controller_test.rb +87 -0
 - data/test/rails-app/test/controllers/songs_controller_test.rb +152 -145
 - data/test/rails-app/test/test_helper.rb +7 -1
 - data/test/test_helper.rb +0 -2
 - data/trailblazer-endpoint.gemspec +2 -1
 - metadata +69 -24
 - data/test/rails-app/config/initializers/cookies_serializer.rb +0 -5
 - data/test/rails-app/config/initializers/new_framework_defaults.rb +0 -24
 - data/test/rails-app/config/initializers/session_store.rb +0 -3
 - data/test/rails-app/config/secrets.yml +0 -22
 - data/test/rails-app/test/helpers/.keep +0 -0
 - data/test/rails-app/test/integration/.keep +0 -0
 - data/test/rails-app/test/mailers/.keep +0 -0
 - data/test/rails-app/vendor/assets/javascripts/.keep +0 -0
 - data/test/rails-app/vendor/assets/stylesheets/.keep +0 -0
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: be47945174c82b64947b1f14951b66c9395b65caf4bcb221792f50cae38bf25a
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 67b8254e1c2775f6909f29cb7779635d38412a3ec972c350ad49cb0e287d1131
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: eddf0ed3f16dd28c3fbebe2d9170e763ddc40f785f2ecd752cecd56ef2b9c3bc96c3dd4d8361cf170a9f997025dfd52316b2b9b799fe09dcf2720955903c5240
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 2fe89f93da8356a1f13e7b229f1a1137ddd0ee8c453c10858254097a42c1213e3e1dcdd23994eb2f4f16568e66ee696e3c0dfaeec0777f321931da98eca8691c
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/Appraisals
    ADDED
    
    
    
        data/CHANGES.md
    CHANGED
    
    | 
         @@ -1,3 +1,30 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # 0.0.8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            * Add `Protocol.insert_copy_from_domain_ctx!` to copy from `domain_ctx` to the `endpoint_ctx`.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            # 0.0.7
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            * BREAKING: Remove `:domain_ctx_filter` in favor of `Controller.insert_copy_to_domain_ctx!`.
         
     | 
| 
      
 8 
     | 
    
         
            +
            * Add support for serializing `:suspend_data` and deserializing `:resume_data` so session data can get automatically encrypted and passed to the next action. This used to sit in `workflow`.
         
     | 
| 
      
 9 
     | 
    
         
            +
            * Add `:find_process_model`. This introduces a new protocol step before `policy` to find the "process model" instead of letting the domain operation or even the policy (or both!) find the "current model".
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            # 0.0.6
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            * `Controller::endpoint` short form introduced.
         
     | 
| 
      
 14 
     | 
    
         
            +
            * Minor changes for `Controller.module`.
         
     | 
| 
      
 15 
     | 
    
         
            +
            * Lots of cleanups.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            # 0.0.5
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            * Removed `Protocol::Failure`. Until we have `Railway::End::Failure`, use a normal `Activity::End` everywhere instead of introducing our own.
         
     | 
| 
      
 20 
     | 
    
         
            +
            * Default `with_or_etc:invoke` is `TaskWrap.invoke`.
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # 0.0.4
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            * Use new `context-0.3.1`.
         
     | 
| 
      
 25 
     | 
    
         
            +
            * Don't use `wtf?`.
         
     | 
| 
      
 26 
     | 
    
         
            +
            * Don't create a `Context` anymore in `Endpoint.arguments_for`.
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
       1 
28 
     | 
    
         
             
            # 0.0.3
         
     | 
| 
       2 
29 
     | 
    
         | 
| 
       3 
30 
     | 
    
         
             
            * Introduce `Options`.
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,11 +1,46 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Trailblazer::Endpoint
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            * 
     | 
| 
      
 3 
     | 
    
         
            +
            *Endpoints handle authentication, authorization, calling the business logic and response rendering.*
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Overview
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
            An endpoint links your routing with your business code. The idea is that your controllers are pure HTTP routers, calling the respective endpoint for each action. From there, the endpoint takes over, handles authentication, policies, executing the domain code, interpreting the result, and providing hooks to render a response.
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
            Instead of dealing with a mix of `before_filter`s, Rack-middlewares, controller code and callbacks, an endpoint is just another activity and allows to be customized with the well-established Trailblazer mechanics.
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            In a Rails controller, a controller action could look as follows.
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 15 
     | 
    
         
            +
            class DiagramsController < ApplicationController
         
     | 
| 
      
 16 
     | 
    
         
            +
              endpoint Diagram::Operation::Create, [:is_logged_in?, :can_add_diagram?]
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def create
         
     | 
| 
      
 19 
     | 
    
         
            +
                endpoint Diagram::Operation::Create do |ctx, **|
         
     | 
| 
      
 20 
     | 
    
         
            +
                  redirect_to diagram_path(ctx[:diagram].id)
         
     | 
| 
      
 21 
     | 
    
         
            +
                end.Or do |ctx, **|
         
     | 
| 
      
 22 
     | 
    
         
            +
                  render :form
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
            ```
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            While routing and redirecting/rendering still happens in Rails, all remaining steps are handled in the endpoint.
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            An API controller action, where the rendering is done generically, could look much simpler.
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 33 
     | 
    
         
            +
            class API::V1::DiagramsController < ApplicationController
         
     | 
| 
      
 34 
     | 
    
         
            +
              endpoint Diagram::Operation::Create, [:is_logged_in?, :can_add_diagram?]
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              def create
         
     | 
| 
      
 37 
     | 
    
         
            +
                endpoint Diagram::Operation::Create
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
      
 40 
     | 
    
         
            +
            ```
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            Endpoints are easily customized but their main intent is to reduce fuzzy controller code and providing best practices for both HTML-rendering controllers and APIs.
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            ## Documentation
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            Read the [full documentation for endpoint](https://trailblazer.to/2.1/docs/endpoint.html) on our website.
         
     | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -5,6 +5,12 @@ task :default => [:test] 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            Rake::TestTask.new(:test) do |test|
         
     | 
| 
       7 
7 
     | 
    
         
             
              test.libs << 'test'
         
     | 
| 
       8 
     | 
    
         
            -
              test.test_files = FileList['test/endpoint_test.rb', 'test/docs/*_test.rb', "test/adapter/*_test.rb"]
         
     | 
| 
      
 8 
     | 
    
         
            +
              test.test_files = FileList['test/endpoint_test.rb', 'test/docs/*_test.rb', "test/adapter/*_test.rb", "test/config_test.rb"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              test.verbose = true
         
     | 
| 
      
 10 
     | 
    
         
            +
            end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            Rake::TestTask.new('test-rails-app') do |test|
         
     | 
| 
      
 13 
     | 
    
         
            +
              test.libs << 'test'
         
     | 
| 
      
 14 
     | 
    
         
            +
              test.test_files = FileList['test/rails-app/test/test_helper.rb', 'test/rails-app/test/**/*.rb']
         
     | 
| 
       9 
15 
     | 
    
         
             
              test.verbose = true
         
     | 
| 
       10 
16 
     | 
    
         
             
            end
         
     | 
    
        data/lib/trailblazer/endpoint.rb
    CHANGED
    
    | 
         @@ -2,8 +2,12 @@ module Trailblazer 
     | 
|
| 
       2 
2 
     | 
    
         
             
              class Endpoint
         
     | 
| 
       3 
3 
     | 
    
         
             
                # Create an {Endpoint} class with the provided adapter and protocol.
         
     | 
| 
       4 
4 
     | 
    
         
             
                # This builder also sets up taskWrap filters around the {domain_activity} execution.
         
     | 
| 
       5 
     | 
    
         
            -
                def self.build(protocol:, adapter:, domain_activity:, scope_domain_ctx: true,  
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
                def self.build(protocol:, adapter:, domain_activity:, scope_domain_ctx: true, protocol_block: ->(*) { Hash.new },
         
     | 
| 
      
 6 
     | 
    
         
            +
                  serialize: false, # TODO: plug-in, not hardcoded!
         
     | 
| 
      
 7 
     | 
    
         
            +
                  deserialize: false,# TODO: plug-in, not hardcoded!
         
     | 
| 
      
 8 
     | 
    
         
            +
                  find_process_model: false, # TODO: plug-in, not hardcoded!
         
     | 
| 
      
 9 
     | 
    
         
            +
                  deserialize_process_model_id_from_resume_data: false # TODO: plug-in, not hardcoded!
         
     | 
| 
      
 10 
     | 
    
         
            +
                  )
         
     | 
| 
       7 
11 
     | 
    
         
             
                  # special considerations around the {domain_activity} and its taskWrap:
         
     | 
| 
       8 
12 
     | 
    
         
             
                  #
         
     | 
| 
       9 
13 
     | 
    
         
             
                  #  1. domain_ctx_filter (e.g. to filter {current_user})
         
     | 
| 
         @@ -20,24 +24,49 @@ module Trailblazer 
     | 
|
| 
       20 
24 
     | 
    
         
             
                  # scoping: {:domain_ctx} becomes ctx
         
     | 
| 
       21 
25 
     | 
    
         
             
                  extensions_options.merge!(Endpoint.options_for_scope_domain_ctx) if scope_domain_ctx # TODO: test flag
         
     | 
| 
       22 
26 
     | 
    
         | 
| 
      
 27 
     | 
    
         
            +
                  app_protocol = build_protocol(protocol, domain_activity: domain_activity, extensions_options: extensions_options, protocol_block: protocol_block, serialize: serialize, deserialize: deserialize,
         
     | 
| 
      
 28 
     | 
    
         
            +
                    find_process_model: find_process_model, deserialize_process_model_id_from_resume_data: deserialize_process_model_id_from_resume_data
         
     | 
| 
      
 29 
     | 
    
         
            +
                    )
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # puts Trailblazer::Developer.render(app_protocol)
         
     | 
| 
       23 
32 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
                   
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 33 
     | 
    
         
            +
                  Class.new(adapter) do
         
     | 
| 
      
 34 
     | 
    
         
            +
                    step(Subprocess(app_protocol), {inherit: true, id: :protocol, replace: :protocol})
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end # app_adapter
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                # @private
         
     | 
| 
      
 40 
     | 
    
         
            +
                def self.build_protocol(protocol, domain_activity:, extensions_options:, protocol_block:, serialize:, deserialize:, find_process_model:, deserialize_process_model_id_from_resume_data:)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  Class.new(protocol) do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    if serialize
         
     | 
| 
      
 43 
     | 
    
         
            +
                      Protocol::Controller.insert_serialize_steps!(self)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    if deserialize
         
     | 
| 
      
 47 
     | 
    
         
            +
                      Protocol::Controller.insert_deserialize_steps!(self)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    if serialize || deserialize
         
     | 
| 
      
 51 
     | 
    
         
            +
                      Protocol::Controller.insert_copy_to_domain_ctx!(self, :resume_data => :resume_data)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    if find_process_model
         
     | 
| 
      
 55 
     | 
    
         
            +
                      Protocol::Controller.insert_find_process_model!(self, before: :policy) # TODO: test before: :policy
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    if deserialize_process_model_id_from_resume_data
         
     | 
| 
      
 59 
     | 
    
         
            +
                      pass Protocol::Controller.method(:deserialize_process_model_id_from_resume_data), after: :deserialize_resume_data, magnetic_to: :deserialize, Output(:success) => Track(:deserialize)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
       26 
61 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                  app_protocol = Class.new(protocol) do
         
     | 
| 
       28 
62 
     | 
    
         
             
                    step(Subprocess(domain_activity), {inherit: true, id: :domain_activity, replace: :domain_activity,
         
     | 
| 
       29 
63 
     | 
    
         | 
| 
       30 
64 
     | 
    
         
             
            # FIXME: where does this go?
         
     | 
| 
       31 
65 
     | 
    
         
             
                    }.
         
     | 
| 
       32 
66 
     | 
    
         
             
                      merge(extensions_options).
         
     | 
| 
       33 
     | 
    
         
            -
                      merge(instance_exec(& 
     | 
| 
      
 67 
     | 
    
         
            +
                      merge(instance_exec(&protocol_block)) # the block is evaluated in the {Protocol} context.
         
     | 
| 
       34 
68 
     | 
    
         
             
                    )
         
     | 
| 
       35 
69 
     | 
    
         
             
                  end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                  Class.new(adapter) do
         
     | 
| 
       38 
     | 
    
         
            -
                    step(Subprocess(app_protocol), {inherit: true, id: :protocol, replace: :protocol})
         
     | 
| 
       39 
     | 
    
         
            -
                  end # app_adapter
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
70 
     | 
    
         
             
                end
         
     | 
| 
       42 
71 
     | 
    
         | 
| 
       43 
72 
     | 
    
         
             
                def self.options_for_scope_domain_ctx()
         
     | 
| 
         @@ -49,10 +78,13 @@ module Trailblazer 
     | 
|
| 
       49 
78 
     | 
    
         | 
| 
       50 
79 
     | 
    
         
             
                # Runtime
         
     | 
| 
       51 
80 
     | 
    
         
             
                # Invokes the endpoint for you and runs one of the three outcome blocks.
         
     | 
| 
       52 
     | 
    
         
            -
                def self.with_or_etc(activity, args, failure_block:, success_block:, protocol_failure_block:)
         
     | 
| 
      
 81 
     | 
    
         
            +
                def self.with_or_etc(activity, args, failure_block:, success_block:, protocol_failure_block:, invoke: Trailblazer::Activity::TaskWrap.method(:invoke))
         
     | 
| 
      
 82 
     | 
    
         
            +
                # def self.with_or_etc(activity, args, failure_block:, success_block:, protocol_failure_block:, invoke: Trailblazer::Developer.method(:wtf?))
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
       53 
84 
     | 
    
         
             
                  # args[1] = args[1].merge(focus_on: { variables: [:returned], steps: :invoke_workflow })
         
     | 
| 
       54 
85 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                  signal, (endpoint_ctx, _ ) = Trailblazer::Developer.wtf?(activity, args)
         
     | 
| 
      
 86 
     | 
    
         
            +
                  # signal, (endpoint_ctx, _ ) = Trailblazer::Developer.wtf?(activity, args)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  signal, (endpoint_ctx, _ ) = invoke.call(activity, args) # translates to Trailblazer::Developer.wtf?(activity, args)
         
     | 
| 
       56 
88 
     | 
    
         | 
| 
       57 
89 
     | 
    
         
             
                  # this ctx is passed to the controller block.
         
     | 
| 
       58 
90 
     | 
    
         
             
                  block_ctx = endpoint_ctx[:domain_ctx].merge(endpoint_ctx: endpoint_ctx, signal: signal, errors: endpoint_ctx[:errors]) # DISCUSS: errors? status?
         
     | 
| 
         @@ -77,7 +109,8 @@ module Trailblazer 
     | 
|
| 
       77 
109 
     | 
    
         | 
| 
       78 
110 
     | 
    
         
             
                #@ For WORKFLOW and operations. not sure this method will stay here.
         
     | 
| 
       79 
111 
     | 
    
         
             
                def self.arguments_for(domain_ctx:, flow_options:, circuit_options: {}, **endpoint_options)
         
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
      
 112 
     | 
    
         
            +
                  # we don't have to create the Ctx wrapping explicitly here. this is done via `:input`.
         
     | 
| 
      
 113 
     | 
    
         
            +
                  # domain_ctx      = Trailblazer::Context::IndifferentAccess.build(domain_ctx, {}, [domain_ctx, flow_options], circuit_options)
         
     | 
| 
       81 
114 
     | 
    
         | 
| 
       82 
115 
     | 
    
         
             
                  [
         
     | 
| 
       83 
116 
     | 
    
         
             
                    [
         
     | 
| 
         @@ -128,3 +161,6 @@ require "trailblazer/endpoint/adapter" 
     | 
|
| 
       128 
161 
     | 
    
         
             
            require "trailblazer/endpoint/dsl"
         
     | 
| 
       129 
162 
     | 
    
         
             
            require "trailblazer/endpoint/controller"
         
     | 
| 
       130 
163 
     | 
    
         
             
            require "trailblazer/endpoint/options"
         
     | 
| 
      
 164 
     | 
    
         
            +
            require "trailblazer/endpoint/protocol/controller"
         
     | 
| 
      
 165 
     | 
    
         
            +
            require "trailblazer/endpoint/protocol/find_process_model"
         
     | 
| 
      
 166 
     | 
    
         
            +
            require "trailblazer/endpoint/protocol/cipher"
         
     | 
| 
         @@ -9,20 +9,32 @@ module Trailblazer 
     | 
|
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
                module Adapter
         
     | 
| 
       12 
     | 
    
         
            -
                  class Web <Trailblazer::Activity:: 
     | 
| 
      
 12 
     | 
    
         
            +
                  class Web < Trailblazer::Activity::Path
         
     | 
| 
       13 
13 
     | 
    
         
             
                    _404_path = ->(*) { step :_404_status }
         
     | 
| 
       14 
14 
     | 
    
         
             
                    _401_path = ->(*) { step :_401_status }
         
     | 
| 
       15 
15 
     | 
    
         
             
                    _403_path = ->(*) { step :_403_status }
         
     | 
| 
       16 
16 
     | 
    
         
             
                    # _422_path = ->(*) { step :_422_status } # TODO: this is currently represented by the {failure} track.
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
      
 18 
     | 
    
         
            +
                    # FIXME: is this really the only way to add an {End} to all this?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @state.update_sequence do |sequence:, **|
         
     | 
| 
      
 20 
     | 
    
         
            +
                      sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :fail_fast), magnetic_to: :fail_fast, id: "End.fail_fast") # TODO: rename to {protocol_failure}
         
     | 
| 
      
 21 
     | 
    
         
            +
                      sequence = Activity::Path::DSL.append_end(sequence, task: Activity::End.new(semantic: :failure), magnetic_to: :failure, id: "End.failure")
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                      recompile_activity!(sequence)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                      sequence
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
       18 
28 
     | 
    
         
             
                    step Subprocess(Protocol), # this will get replaced
         
     | 
| 
       19 
29 
     | 
    
         
             
                      id: :protocol,
         
     | 
| 
       20 
30 
     | 
    
         
             
                      Output(:not_authorized)     => Path(track_color: :not_authorized, connect_to: Id(:protocol_failure), &_403_path),
         
     | 
| 
       21 
31 
     | 
    
         
             
                      Output(:not_found)          => Path(track_color: :not_found, connect_to: Id(:protocol_failure), &_404_path),
         
     | 
| 
       22 
32 
     | 
    
         
             
                      Output(:not_authenticated)  => Path(track_color: :not_authenticated, connect_to: Id(:protocol_failure), &_401_path),
         
     | 
| 
       23 
     | 
    
         
            -
                      Output(:invalid_data)       => Track(:failure) # application error, since it's usually a failed validation.
         
     | 
| 
      
 33 
     | 
    
         
            +
                      Output(:invalid_data)       => Track(:failure), # application error, since it's usually a failed validation.
         
     | 
| 
      
 34 
     | 
    
         
            +
                      Output(:failure)       => Track(:failure) # application error, since it's usually a failed validation.
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    step :protocol_failure, magnetic_to: nil, Output(:success) => Track(:fail_fast)#, Output(:failure) => Track(:fail_fast)
         
     | 
| 
       24 
37 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                    step :protocol_failure, magnetic_to: nil, Output(:success) => Track(:fail_fast), Output(:failure) => Track(:fail_fast)
         
     | 
| 
       26 
38 
     | 
    
         | 
| 
       27 
39 
     | 
    
         
             
                    def protocol_failure(ctx, **)
         
     | 
| 
       28 
40 
     | 
    
         
             
                      true
         
     | 
| 
         @@ -41,28 +53,34 @@ module Trailblazer 
     | 
|
| 
       41 
53 
     | 
    
         
             
                    def _403_status(ctx, **)
         
     | 
| 
       42 
54 
     | 
    
         
             
                      ctx[:status] = 403
         
     | 
| 
       43 
55 
     | 
    
         
             
                    end
         
     | 
| 
       44 
     | 
    
         
            -
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end # Web
         
     | 
| 
       45 
57 
     | 
    
         | 
| 
       46 
58 
     | 
    
         
             
                  class API < Web
         
     | 
| 
       47 
59 
     | 
    
         
             
                    step :_200_status, after: :protocol
         
     | 
| 
       48 
60 
     | 
    
         | 
| 
       49 
     | 
    
         
            -
                    def _200_status(ctx, **)
         
     | 
| 
       50 
     | 
    
         
            -
                      ctx[:status] =  
     | 
| 
      
 61 
     | 
    
         
            +
                    def _200_status(ctx, success_status: 200, **)
         
     | 
| 
      
 62 
     | 
    
         
            +
                      ctx[:status] = success_status
         
     | 
| 
       51 
63 
     | 
    
         
             
                    end
         
     | 
| 
       52 
64 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                     
     | 
| 
      
 65 
     | 
    
         
            +
                    step :_422_status, before: "End.failure", magnetic_to: :failure, Output(:success) => Track(:failure)
         
     | 
| 
       54 
66 
     | 
    
         | 
| 
       55 
67 
     | 
    
         
             
                    def _422_status(ctx, **)
         
     | 
| 
       56 
68 
     | 
    
         
             
                      ctx[:status] = 422
         
     | 
| 
       57 
69 
     | 
    
         
             
                    end
         
     | 
| 
       58 
70 
     | 
    
         | 
| 
       59 
71 
     | 
    
         | 
| 
       60 
     | 
    
         
            -
                    def self.insert_error_handler_steps(adapter)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    def self.insert_error_handler_steps(adapter) # TODO: evaluate if needed?
         
     | 
| 
       61 
73 
     | 
    
         
             
                      adapter = Class.new(adapter) do
         
     | 
| 
       62 
     | 
    
         
            -
                         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
                        API.insert_error_handler_steps!(self)
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    def self.insert_error_handler_steps!(adapter)
         
     | 
| 
      
 79 
     | 
    
         
            +
                      adapter.instance_exec do
         
     | 
| 
      
 80 
     | 
    
         
            +
                        step :handle_not_authenticated, magnetic_to: :not_authenticated, Output(:success) => Track(:not_authenticated), before: :_401_status
         
     | 
| 
      
 81 
     | 
    
         
            +
                        step :handle_not_authorized, magnetic_to: :not_authorized, Output(:success) => Track(:not_authorized), before: :_403_status
         
     | 
| 
       64 
82 
     | 
    
         
             
                        # step :handle_not_found, magnetic_to: :not_found, Output(:success) => Track(:not_found), Output(:failure) => Track(:not_found)
         
     | 
| 
       65 
     | 
    
         
            -
                         
     | 
| 
      
 83 
     | 
    
         
            +
                        step :handle_invalid_data, before: :_422_status, magnetic_to: :failure, Output(:success) => Track(:failure)
         
     | 
| 
       66 
84 
     | 
    
         
             
                      end
         
     | 
| 
       67 
85 
     | 
    
         
             
                    end
         
     | 
| 
       68 
86 
     | 
    
         | 
| 
         @@ -81,117 +99,8 @@ module Trailblazer 
     | 
|
| 
       81 
99 
     | 
    
         
             
                        end
         
     | 
| 
       82 
100 
     | 
    
         
             
                      end
         
     | 
| 
       83 
101 
     | 
    
         
             
                    end
         
     | 
| 
       84 
     | 
    
         
            -
                  end
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                  # Basic endpoint adapter for a HTTP document API.
         
     | 
| 
       87 
     | 
    
         
            -
                  # As always: "work in progress" ;)
         
     | 
| 
       88 
     | 
    
         
            -
                  #
         
     | 
| 
       89 
     | 
    
         
            -
                  # {End.fail_fast} currently implies a 4xx-able error.
         
     | 
| 
       90 
     | 
    
         
            -
                  class API_ < Trailblazer::Activity::FastTrack
         
     | 
| 
       91 
     | 
    
         
            -
                    _404_path = ->(*) { step :_404_status }
         
     | 
| 
       92 
     | 
    
         
            -
                    _401_path = ->(*) { step :_401_status; step :_401_error_message }
         
     | 
| 
       93 
     | 
    
         
            -
                    _403_path = ->(*) { step :_403_status }
         
     | 
| 
       94 
     | 
    
         
            -
                    # _422_path = ->(*) { step :_422_status } # TODO: this is currently represented by the {failure} track.
         
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
                    # The API Adapter automatically wires well-defined outputs for you to well-defined paths. :)
         
     | 
| 
       97 
     | 
    
         
            -
            # FIXME
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
                    step Subprocess(Protocol), # this will get replaced
         
     | 
| 
       100 
     | 
    
         
            -
                      id: :protocol,
         
     | 
| 
       101 
     | 
    
         
            -
                      Output(:not_authorized)     => Path(track_color: :_403, connect_to: Id(:render_protocol_failure_config), &_403_path),
         
     | 
| 
       102 
     | 
    
         
            -
                      Output(:not_found)          => Path(track_color: :_404, connect_to: Id(:protocol_failure), &_404_path),
         
     | 
| 
       103 
     | 
    
         
            -
                      Output(:not_authenticated)  => Path(track_color: :_401, connect_to: Id(:render_protocol_failure_config), &_401_path),       # head(401), representer: Representer::Error, message: no token
         
     | 
| 
       104 
     | 
    
         
            -
                      Output(:invalid_data)       => Track(:failure) # application error, since it's usually a failed validation.
         
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
                        # extensions: [Trailblazer::Activity::TaskWrap::Extension(merge: TERMINUS_HANDLER)]
         
     | 
| 
       107 
     | 
    
         
            -
                        # failure is automatically wired to failure, being an "application error" vs. a "protocol error (auth, etc)"
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
                        fail :failure_render_config
         
     | 
| 
       111 
     | 
    
         
            -
                        fail :failure_config_status
         
     | 
| 
       112 
     | 
    
         
            -
                        fail :render_failure
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                        step :success_render_config
         
     | 
| 
       115 
     | 
    
         
            -
                        step :success_render_status
         
     | 
| 
       116 
     | 
    
         
            -
                        step :render_success
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
                      # DISCUSS: "protocol failure" and "application failure" should be the same path, probably?
         
     | 
| 
       120 
     | 
    
         
            -
                      step :render_protocol_failure_config, magnetic_to: nil, Output(:success) => Path(connect_to: Id("End.fail_fast")) do
         
     | 
| 
       121 
     | 
    
         
            -
                        step :render_protocol_failure
         
     | 
| 
       122 
     | 
    
         
            -
                        step :protocol_failure
         
     | 
| 
       123 
     | 
    
         
            -
                      end
         
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
            =begin
         
     | 
| 
       126 
     | 
    
         
            -
                      render_protocol_failure_config # representer
         
     | 
| 
       127 
     | 
    
         
            -
                      render_protocol_failure        # Representer.new
         
     | 
| 
       128 
     | 
    
         
            -
                      protocol_failure               # true
         
     | 
| 
       129 
     | 
    
         
            -
            =end
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                    def success_render_status(ctx, **)
         
     | 
| 
       132 
     | 
    
         
            -
                      ctx[:status] = 200
         
     | 
| 
       133 
     | 
    
         
            -
                    end
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                    def success_render_config(ctx, representer:, **)
         
     | 
| 
       136 
     | 
    
         
            -
                      true
         
     | 
| 
       137 
     | 
    
         
            -
                    end
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
                    def render_protocol_failure_config(*args)
         
     | 
| 
       140 
     | 
    
         
            -
                      failure_render_config(*args)
         
     | 
| 
       141 
     | 
    
         
            -
                    end
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
            # ROAR
         
     | 
| 
       144 
     | 
    
         
            -
                    def render_success(ctx, representer:, domain_ctx:, **)
         
     | 
| 
       145 
     | 
    
         
            -
                      model = domain_ctx[:model]
         
     | 
| 
       146 
     | 
    
         
            -
                      ctx[:json] = representer.new(model).to_json # FIXME: use the same as render_failure.
         
     | 
| 
       147 
     | 
    
         
            -
                    end
         
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
                    def failure_render_config(ctx, error_representer:, **)
         
     | 
| 
       150 
     | 
    
         
            -
                      ctx[:representer] = error_representer
         
     | 
| 
       151 
     | 
    
         
            -
                    end
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
                    def failure_config_status(ctx, **)
         
     | 
| 
       154 
     | 
    
         
            -
                      ctx[:status] = 422
         
     | 
| 
       155 
     | 
    
         
            -
                    end
         
     | 
| 
       156 
     | 
    
         
            -
             
     | 
| 
       157 
     | 
    
         
            -
                    def protocol_failure(*args)
         
     | 
| 
       158 
     | 
    
         
            -
                      #failure_config(*args)
         
     | 
| 
       159 
     | 
    
         
            -
                      true
         
     | 
| 
       160 
     | 
    
         
            -
                    end
         
     | 
| 
       161 
     | 
    
         
            -
                    def render_protocol_failure(*args)
         
     | 
| 
       162 
     | 
    
         
            -
                      render_failure(*args)
         
     | 
| 
       163 
     | 
    
         
            -
                    end
         
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
     | 
    
         
            -
                  # ROAR
         
     | 
| 
       166 
     | 
    
         
            -
                    def render_failure(ctx, error_representer:, errors:, **)
         
     | 
| 
       167 
     | 
    
         
            -
                      # render_success(*args)
         
     | 
| 
       168 
     | 
    
         
            -
                      ctx[:json] = error_representer.new(errors).to_json
         
     | 
| 
       169 
     | 
    
         
            -
                  end
         
     | 
| 
       170 
     | 
    
         
            -
              # how/where would we configure each endpoint? (per action)
         
     | 
| 
       171 
     | 
    
         
            -
                # class Endpoint
         
     | 
| 
       172 
     | 
    
         
            -
                #   representer ...
         
     | 
| 
       173 
     | 
    
         
            -
                #   message ...
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
                    def _401_status(ctx, **)
         
     | 
| 
       176 
     | 
    
         
            -
                      ctx[:status] = 401
         
     | 
| 
       177 
     | 
    
         
            -
                    end
         
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
     | 
    
         
            -
                    def _404_status(ctx, **)
         
     | 
| 
       180 
     | 
    
         
            -
                      ctx[:status] = 404
         
     | 
| 
       181 
     | 
    
         
            -
                    end
         
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
                    def _403_status(ctx, **)
         
     | 
| 
       184 
     | 
    
         
            -
                      ctx[:status] = 403
         
     | 
| 
       185 
     | 
    
         
            -
                    end
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                    def _401_error_message(ctx, **)
         
     | 
| 
       188 
     | 
    
         
            -
                      ctx[:error_message] = "Authentication credentials were not provided or invalid."
         
     | 
| 
       189 
     | 
    
         
            -
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end # API
         
     | 
| 
       190 
103 
     | 
    
         | 
| 
       191 
     | 
    
         
            -
                    # def exec_success(ctx, success_block:, **)
         
     | 
| 
       192 
     | 
    
         
            -
                    #   success_block.call(ctx, **ctx.to_hash) # DISCUSS: use Nested(dynamic) ?
         
     | 
| 
       193 
     | 
    
         
            -
                    # end
         
     | 
| 
       194 
     | 
    
         
            -
                  end
         
     | 
| 
       195 
104 
     | 
    
         
             
                end
         
     | 
| 
       196 
105 
     | 
    
         
             
              end
         
     | 
| 
       197 
106 
     | 
    
         
             
            end
         
     |