How can a custom filter be added to the HttpPipeline using afBedSheet?

71 views Asked by At

The afBedSheet documentation says that "Filters can be used to address cross cutting concerns such as authorisation." and shows this code snippet:

@Contribute { serviceType=HttpPipeline# }
static Void contributeHttpPipeline(OrderedConfig conf, AuthFilter myAuthFilter) {
  conf.addOrdered("AuthFilter", myAuthFilter, ["after: BedSheetFilters"])
}

I'm trying to implement an AuthFilter (a dummy now but to be evolved into a real AuthFilter) but I can't get it to work:

using afBedSheet

const mixin AuthFilter : HttpPipelineFilter { }

internal const class AuthFilterImpl : AuthFilter {

    internal new make(|This|in) { in(this) }

    override Bool service(HttpPipeline handler) {
        echo("Dummy AuthFilter invoked!")
        return handler.service
    }
}

I can successfully build the project, but when I run it and invoke any HTTP service I get the error below. I believe I have to declare or annotate my AuthFilter as an afIoc service, but don't know where or how. Can anyone show me how, please?

Thread Locals:
  ThreadStash.01.BedSheetModule.0017.perThreadState: fan.afIoc.ModuleServices@1ab5e0b
  ThreadStash.01.HttpRequest.0001.headers: fan.afBedSheet.HttpRequestHeaders@1ab6087
  afIoc::ThreadStash.counter: 13
  web.req: fan.wisp.WispReq@4e62cc
  web.res: fan.wisp.WispRes@387bc2
  web.session: 060f9951-41f1-e500-0fc2-0019b971d079
[05:27:18 05-Nov-13] [err] [web] Internal error processing: /info
  afIoc::IocErr: No dependency matches type mt::AuthFilter.
Ioc Operation Trace:
  [ 1] Locating dependency by type 'afBedSheet::HttpPipeline'
  [ 2] Creating REAL Service 'HttpPipeline'
  [ 3] Creating Service 'HttpPipeline' via a builder method 'afBedSheet::BedSheetModule.buildHttpPipeline'
  [ 4] Determining injection parameters for afBedSheet::HttpPipeline buildHttpPipeline(afBedSheet::HttpPipelineFilter[] filters, afIoc::PipelineBuilder bob, afIoc::Registry reg)
  [ 5] Looking for dependency of type afBedSheet::HttpPipelineFilter[]
  [ 6] Gathering ORDERED configuration of type afBedSheet::HttpPipelineFilter[]
  [ 7] Determining injection parameters for sys::Void contributeHttpPipeline(afIoc::OrderedConfig conf, mt::AuthFilter
myAuthFilter)
  [ 8] Looking for dependency of type mt::AuthFilter
Stack Trace:
    afIoc::Utils.stackTraceFilter (Utils.fan:63)
    afIoc::RegistryImpl.dependencyByType (RegistryImpl.fan:243)
    afBedSheet::BedSheetWebMod.onService (BedSheetWebMod.fan:34)
    wisp::WispActor.doService (WispActor.fan:197)
    wisp::WispActor.process (WispActor.fan:78)
    wisp::WispActor.receive (WispActor.fan:48)
    concurrent::Actor._dispatch (Actor.java:228)
    concurrent::Actor._work (Actor.java:199)
    concurrent::ThreadPool$Worker.run (ThreadPool.java:255)
1

There are 1 answers

0
Steve Eynon On BEST ANSWER

AuthFilter does not need to be declared as a service - you could new up an instance in the contribute() method:

@Contribute { serviceType=HttpPipeline# }
static Void contributeHttpPipeline(OrderedConfig conf) {

    authFilter := AuthFilterImpl()

    conf.addOrdered("AuthFilter", authFilter, ["after: BedSheetFilters"])
}

If AuthFilter has dependencies on other services (for example, it has fields annotated with @Inject) then afIoc should build the instance for you. The OrderedConfig and MappedConfig objects have a handy autobuild() method just for this:

    authFilter := conf.autobuild(AuthFilterImpl#)

If you want AuthFilter to be injected into other services, or you want to contribute to it, then it needs to be defined as an afIoc service. Use the bind() method in your AppModule to do this:

static Void bind(ServiceBinder binder) {
    binder.bind(AuthFilter#, AuthFilterImpl#)
}

It may then be parameter injected into the contribute method, just as you had in your example:

@Contribute { serviceType=HttpPipeline# }
static Void contributeHttpPipeline(OrderedConfig conf, AuthFilter authFilter) {

    conf.addOrdered("AuthFilter", authFilter, ["after: BedSheetFilters"])
}

See afIoc - definingServices for more details. The BedSheetModule may also be a good reference for afIoc examples.