Comments (13)
So as I'm working on #8 I figured I would add my own thoughts around this. When it configuration, different web frameworks have different ways of going about it. The two chief ways I can think of are:
- Parsing from a config file/environment
- Programatic control.
There are pros and cons to both of them, but I think the most flexible solution would be to have a set of defaults, which are overridden by values parsed from the environment and these can be further overridden by programatic configuration.
I think this is a good idea because for someone who just wants to set up a quick service, they will have sane defaults to work with, while setting up configuration to be read from a file/environment will help make deployments flexible. On top of that, we can provide specific control over individual routes as presented by @aturon .
from tide.
I've tried to use typemap, but cloneable one yields forward compatibility warning regarding object safety.
warning: the trait `typemap::internals::CloneAny` cannot be made into an object
--> /home/tirr/.cargo/registry/src/github.com-1ecc6299db9ec823/typemap-0.3.3/src/internals.rs:33:5
|
33 | fn clone_any_send(&self) -> Box<CloneAny + Send> where Self: Send;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(where_clauses_object_safety)] on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>
= note: method `clone_any_send` references the `Self` type in where clauses
(...)
from tide.
How about we just have a config struct with a few fields to start with and wrap it in an Arc to be shared across? My reasoning is that for the most part configuration is for configuring the framework, so the number of knobs that a user can turn are limited.
So we can have default values set up which are overridden with the parsed values from a config file/environment which can be further overridden programmatically using something like app.config
.
Just a thought.
from tide.
@tirr-c I experimented with the Extensions
from the HTTP crate and it compiled without any issues. As an experiment I added it to the App
struct and created a dummy config to be stored in it, and it worked.
I'm not sure how this typemap will be shared internally within Tide though.
from tide.
I experimented with the Extensions
type, but the issue I am facing is safely sharing it globally. I used lazy_static to store an instance of Extensions
behind a RwLock
, but the borrow checker is not happy about accessing the data in it.
from tide.
I have an idea that doesn't require global states or typemaps, but is somewhat less flexible -- using toml::Value
(or serde_json::Value
, or whatever) under the hood.
Configuration can be set and retrieved with typed configuration items (like the sample code above.) Those items should implement Serialize
and Deserialize
. Each item has its own unique name in &'static str
and it will be used as the key for the configuration.
trait ConfigurationItem: Serialize + Deserialize + Default {
const NAME: &'static str;
}
When new endpoint is established, configuration of the parent router will be cloned into the endpoint. This is easier to implement, but it makes configuration and resource declaration depend on their order, like nest
and middleware
. Alternatively we can lazily overlap parent and child configuration when parent router setup ends.
A positive side effect of this approach is that it makes implementing configuration files a trivial job, as we can use Serde for serializing and deserializing.
from tide.
@tirr-c Interesting thought! I'm a little worried though that it'd impose some overhead that should be avoidable.
Looking more closely at the warning for CloneAny
, the problem seems to be the method-level where
clauses, which I think are being used just to avoid having to duplicate the trait for various combinations of marker traits (Send
, Sync
) that might apply.
In other words, I bet that we could roll our own version of CloneAny
that inherits from Send
and Sync
, and just have one method that doesn't run into these issues:
trait CloneAny: Send + Sync {
fn clone_any(&self) -> Box<dyn CloneAny>;
}
impl Clone for Box<dyn CloneAny> {
fn clone(&self) -> Self {
self.clone_any()
}
}
@tirr-c do you want to take another stab at using TypeMap<dyn CloneAny>
with the above definition?
from tide.
I'm a little curious about where this configuration typemap will live. I ask because I want to know how an endpoint implementation can access some data in this configuration. Similarly, how will any part of Tide access it?
My bad I did not see the comment on #100 , I agree having this API to tweak the configuration per endpoint is definitely more flexible. So if I'm understanding this right, it means that the configuration will be accessible on the App
and then be copied over to any routers and sub routers?
from tide.
So I was thinking about how to share configuration with middleware and was considering something along the lines of this:
The handle
method of the Middleware
trait can be passed a handle to this context as a parameter.
impl<Data, F> Middleware<Data> for F
where
F: Send + Sync + Fn(RequestContext<Data>) -> FutureObj<Response>,
{
fn handle<'a>(&'a self, ctx: RequestContext<'a, Data>, config: TypeMap<dyn CloneAny>) -> FutureObj<'a, Response> {
(self)(ctx)
}
}
Definitely a rough design, but what do you guys think?
from tide.
@bIgBV I think configuration can be wrapped in RequestContext
. The context struct can provide some methods to retrieve configuration items then.
@aturon I've experimented with your trait design (with some tweaks) and it's promising! However I'm afraid we can't use existing TypeMap
directly with the custom Any
trait as it required implementing internal traits of typemap
. I managed to write a new, simple typemap (this is a proof-of-concept): Playground
from tide.
@tirr-c I was considering RequestContext
as well, but isn't it constructed for every request? Will that mean we will pass the config from the App
/Server
down to the RequestContext
?
from tide.
@bIgBV Well, configuration is per endpoint, so not exactly from the App
; but yes, the config will be from the endpoints, passed by reference. I've opened PR #109 which implements the idea.
from tide.
@tirr-c PR looks really good!
from tide.
Related Issues (20)
- `req.body_json().await?` Get `serde_json::error::Error` HOT 2
- SessionMiddleware and RedisSessionStore HOT 3
- Unexpected Behaviour in 0.17.0-beta.1 HOT 5
- Cookie_string parsed incorrectly when reading an incoming cookie. HOT 4
- dinamycally check allowed origins (or with a regex) HOT 1
- WASM support HOT 2
- How to do RBAC authorization when using tide? HOT 1
- Error messages are not returned HOT 5
- Stop a Tide server (not graceful shutdown) HOT 1
- Support uploads (100 Continue) HOT 4
- Route introspection? HOT 2
- I don't see the code that implements &str for the listen method
- Does tide plan to support http2? HOT 5
- Proposal: Refactor Middleware Execution / Next with Cursors and Async Recursion HOT 1
- Chat link is invalid HOT 1
- serve_dir doesn't seem to work and even panics in some cases HOT 2
- failed to select version 0.17.0 (copied the one given in the doc) and did a cargo run
- Nested endpoints have less priority than wildcards
- Potential security issue HOT 1
- Embed Assets to Binary
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tide.