-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Resources #18
Comments
I agree with |
I'm 👎 as this can be easily implemented outside of Rocket (from what I can tell). Something like |
I'm +1 for the exact reason that @mehcode is -1. I'd actually like to see a Rust framework that takes a batteries included approach like Rails. Rust is very nice for this, because you don't pay for what you don't use (at runtime, anyway--your compile time might go up a little), and you can even use cargo's |
As we think about this issue, keep in mind that Rocket already separates core concepts from extensions via the |
Don't get me wrong. I love this idea. But I could also love #142.
💯 In my opinion, this should be drafted into a separate crate |
I've been thinking a lot about this lately, and here's the sketch of the trait I propose : pub trait RocketResource {
type Id: for<'a> request::FromParam<'a>;
type Requirements: for<'a, 'r> request::FromRequest<'a, 'r>;
type CreateResponse: for<'r> response::Responder<'r>;
type ReadResponse: for<'r> response::Responder<'r>;
type UpdateResponse: for<'r> response::Responder<'r>;
type DeleteResponse: for<'r> response::Responder<'r>;
type Input: data::FromData;
fn create(input: Self::Input, format: http::ContentType, requirements: Self::Requirements)
-> Self::CreateResponse;
fn read(id: Self::Id, format: http::ContentType, requirements: Self::Requirements)
-> Self::ReadResponse;
fn update(input: Self::Input, id: Self::Id, format: http::ContentType, requirements: Self::Requirements)
-> Self::UpdateResponse;
fn delete(id: Self::Id, format: http::ContentType, requirements: Self::Requirements)
-> Self::DeleteResponse;
} From @SergioBenitez proposition :
|
@Meralis40 would this trait be derivable? I think the big win of having a resource is being able to add one annotation and have everything flushed out. If it's not possible to make this derivable, maybe a rails style cli generator could be an option here. The generator could take care of the routes and a common I've been thinking of the best approach for this as well. Maybe the answer is a combination of a trait and generator, I just wanted to get this idea out there. |
I think the best approch is the combination of a trait and generator. Also, :+1 for common I will try to make a working example. Edit : i've modified the todo example to use the trait, see at https://github.com/Meralis40/rocket-resource |
If I had a resource which required an API key to access, how would I express that guard while using the trait? |
The more I think about it, the more I think this trait is not a good fit to Rocket in the current form : for example you can't have your API key on body, it must be an custom header. In addition, if you want several guards for access (imagine an API key with a database and user session loaded), you need another struct for that, only to comply with the trait. Also, if we want to have different data depending on user been admin or not (for example), the user need to implement the logic on the trait (when currently, the auto-generated handler helps). Another potential design can be something like this : #[resource("todo")]
pub mod todo {
struct Todo {
description: String,
completed: bool,
}
#[resource_get("/<id>")]
fn read_one(id: ID, format: ContentType) -> DBResult<Either<Template, JSON<String>>> {
let todo = try!(Database::find_todo(id));
if format.is_json() {
Either::B(JSON(todo.to_string()))
} else {
Either::A(Template::render("todo", &todo))
}
}
}
fn main() {
rocket::ignite().register("/", resources![todo]).launch()
} With:
This design is less code for users, but requires to handle this on |
I think this is not a great idea. In general you would need a little more than CRUD ops for every CRUD style app. The idea described in this issue cannot handle all of that, if you want to handle all of that it might become another diesel project. |
@mmrath Do you have an example? |
This issue has been open for quite some time without any particular progress, and Rocket has evolved significantly since then. I don't believe the concept of resources as suggested in the original issue text makes sense for today's Rocket, so I'm closing this issue. I have some new ideas on what would conceptually be "resources" that I'd like to formalize soon, however. |
An idea I've been toying with is the addition of "resources" to Rocket. This would be similar to
ActiveResource
in Rails. The motivation is that many apps are CRUD-like, and this would remove some of boilerplate of doing this as well as provide more structure when necessary.As an example, consider a
Todo
resource that be created, read, updated, and deleted. Here's what writing this might look like:Note the associated type
ReadResponse
. This can go away entirely onceimpl Trait
is allowed as a return type of trait methods. Then the return type can simply beimpl Response
.This example above would create four routes:
POST todo/
,GET todo/<id>
,PATCH todo/<id>
, andDELETE todo/<id>
mapping to the fourRocketResource
trait methods:create, read, update, delete
.PUT
should likely map toupdate
as well, thoughPATCH
is more appropriate. All of theRocketResource
methods should have default implementation that return a "not-implemented" error of some sort. In the example above, aGET todo/<id>
request would be routed to theread
method, running the logic in the example. Note also theContentType
: resources will respond to any content-type, and the first content-type in theAccept
header will be passed in.Here's a sketch of what the trait might look like:
Of note is the
create
method which takes in an&self
. This is because Rocket will automatically parse the incoming request from forms and JSON. This means that the resource must implementFromForm
andDeserialize
. An alternative is to simply pass inData
instead and let the user decide what to do. Another alternative is to pass in the accepted content-type to theresource
attribute:#[resource("todo", format = "application/json, text/html")]
. In this case, Rocket will return an error on any other kind of request format, and the user is guaranteed thatContentType
will always be one of those in theformat
argument. And, the user will only have to implementFromForm
if they specifytext/html
, andDeserialize
if they specifyapplication/json
, which sounds nice.Anyway, this is a developing thought.
impl Trait
in method return types would make this really nice.The text was updated successfully, but these errors were encountered: