-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split path into outerPath and innerPath, added innerRoute into server (W... #22
base: master
Are you sure you want to change the base?
Conversation
… (Will only look at inner paths inside requests) Signed-off-by: Ben Jackman <[email protected]>
There is some previous discussion in #21 |
I have been looking into doing similar stuff, I am going to be working on this today, so it's still a bit hypothetical trait CgtaApiDirectory {
val marketdataApi : MarketdataApi
val orderdataApi : OrderdataApi
} then I make my client, in the doCall method switch on the first element of the inner path. CgtaApiClient(cfg : Servers) extends autowire.Client{
...
override def doCall(req : Request) {
req.innerPath.toList match {
case "marketdataApi" :: rest => httpRequest(cfg.mdServerUrl, req.copy(innerPath = rest).serialize)
}
}
} then on the server side, I can make a server that handles just the marketdataApi with something like MarketdataServer extends autowire.Server
onRequest { httpReq =>
//Notice MarketdataApi, NOT CgtaApiDirectory
val myMdServerImpl = new MdServerApiImpl()
val router = MarkdataServer.innerRouter[MarketdataApi](myMdServerImpl)
router(httpReq.payload)
} Having that string "marketdataApi" in the client sucks because if the variable get's renamed there is not compile time break so I was thinking about making a macro that converts a member name to a string (memberNamesOf[CgtaApiDirectory].marketdataApi) so if someone renames that member it will break at compile time. Edit: couple typos |
Having thought about this more I think the For your use case, you can trivially set the key to empty, in which case you'll get the local path only, and it'll also be useful for people who want to use the default outer-path, but want to move the file while keeping the outer path the same (e.g. to not-break already-deployed clients). WDYT? |
Traits that are defined before the autowire dependency is included cant I think about it this way, without the outer path the macro just invokes Granted there might be a use case for the client side having the outer path Sent from my tablet.
|
One difference is that I don't want to have to nest two objects/methods awkwardly to rename something =P The My imagined use case is to simply chain up multiple routes with From the way you're describing it, it seems that you may be trying to make autowire fit some pre-defined routing pattern that you already have implemented? That's probably not something that I imagined autowire to do. It's the Scala code that should matter and be kept as simple as possible. |
The idea is if you have object Thing extends Api{
...
} And you decide to rename it to something more sensible object ViewControllerFactory extends Api{
...
} You could do so without breaking anyone via a @key("thing")
object ViewControllerFactory extends Api{
...
} Not sure if that makes sense. For one, it still doesn't allow you do to use the old & the new route simultaneously, so maybe it's not that useful. |
I'm still mulling over the consequences of routing to nested objects. What exactly do you use it for? |
I have several traits I want to be able to call from client side. I group all of those traits together into a larger 'API'. Nesting allows for that For example (this is just illustrative): trait TradingApi {
val cmeMd : Marketdata
val espeedMd : Marketdata
val manualControls : TradingControls
...
}
trait Marketdata {
def getSnapshot(symbol : Symbol, utc : UtcT)
}
trait TradingControls {
def goWide(symbol : FirmSymbol, amount : Int)
def haltTrading(symbol : FirmSymbol)
...
}
trait CompanyApi {
val trading : TradingApi
val reports : ReportingApi
...
}
I can then switch in the client implementation and send cmeMd requests to one server and espeed to another. The requests are sent over HTTP because it's easy to debug and understand, and if we need to do things like proxy or cache, we can use any off the shelf tool for that. |
Would something like this work? @key("CompanyApi.TradingApi")
trait TradingApi {
val cmeMd : Marketdata
val espeedMd : Marketdata
val manualControls : TradingControls
...
}
@key("CompanyApi.MarketData")
trait Marketdata {
def getSnapshot(symbol : Symbol, utc : UtcT)
}
@key("CompanyApi.TradingControls")
trait TradingControls {
def goWide(symbol : FirmSymbol, amount : Int)
def haltTrading(symbol : FirmSymbol)
...
} Not the exact syntax, but the idea of using |
cmeMd and espeedMd would collide in this example I think |
the other benefit to nesting is it really lowers the bar to what can be autowired, so even if you don't want to structure a nested api you can still use nesting where logical in existing traits. I just think if I am designing the API to be used only inside the server, I would use nesting, nothing as insane as the cake pattern mind you, but I would still nest the apis at some point. With nesting, and having a mapping of nesting to requests, Autowire allows presenting the same API as what I would use internally, where I would not be using annotations. |
...ill only look at inner paths inside requests)
Signed-off-by: Ben Jackman [email protected]