Defining two separate API endpoints for essentially the same logic just for the sake of avoiding REST anti-patterns? - laravel

Suppose we have a M:M relationship between a User model and a Project model in a project management SaaS. Naturally we have a pivot table mapping users to projects. An entry is deleted either if the user leaves or if the project manager removes that user from the project.
Even though the final result is essentially the same (i.e., the entry is deleted), I imagine it would be better to distinguish between these two actions by defining two separate API endpoints as follows:
user leaves project
route DELETE /users/{id}/projects/{id}
action UserProjectController#destroy($id) where $id refers to the project
project manager removes user
route DELETE /projects/{id}/participants/{id}
action ProjectParticipantController#destroy($id) where $id refers to the user
Should I ignore Cruddy by Design and RESTful design principles and simply define leave() join() remove() actions instead and use verbs in the URIs? like so:
POST /projects/{id}/join
POST /projects/{id}/leave
POST /projects/{id}/participants/{id}/remove

join,leave,remove are arguably RPC rather than REST. Pivot tables etc are how the domain is implemented and are irrelevant to the caller of the API, which works at the domain level. How do the URLs map to your domain model?
If Project has one or more User why not just use
/projects/{id}/
to manage everything about Project and Participant instances?
User is in a Project but only if
/projects/{id}/participants/{id}
has been called.
FWIW,
DELETE /users/{id}/projects/{id}
looks like it's deleting the Project instance owned by a User as the Project object has participants but the User doesn't use that terminology. Perhaps it would be:
DELETE /users/{id}/projects/{id}/participants
for consistency with the domain model.
However it seems much easier to just use Project to manage Project instances. Removing a User from a Project using the User API seems a convenience that complicates the backend and doesn't really match the Project terminology. That would mean only having UserController and ProjectController classes.
You would have to consider whether a Participant id is the same as a User id and whether the pivot table handles that but that won't affect the API. The API should be an intuitive representation of your domain model.

Something to consider: how would you do it on the web?
Even though the final result is essentially the same (i.e., the entry is deleted), I imagine it would be better to distinguish between these two actions by defining two separate API endpoints
So on the web, you might well have two different forms that are used to "achieve the same result", but that doesn't necessarily mean that the forms should target different resources.
POST /foo
Content-Type: application/x-www-form-urlencoded
action=UnsubscribeUser&otherArguments=....
POST /foo
Content-Type: application/x-www-form-urlencoded
action=CancelProject&otherArguments=....
"One resource or two resources" isn't a question of right or wrong, but rather a question of trade-offs.
POST /projects/{id}/join
POST /projects/{id}/leave
POST /projects/{id}/participants/{id}/remove
That's also "fine"; again, it's a question of trade offs. The machines don't care that your identifiers have a verb in the URI.
They do, somewhat, care whether or not the identifier for reading is the same as the identifier for writing. See RFC 7234.
But it's perfectly reasonable to say that having semantically significant URI spellings in the access log or browser history are more important to our long term success than cache-invalidation.
Keep firmly in mind that DELETE - in the context of HTTP - does not mean the same thing as DELETE in the context of SQL; we're talking about two different name spaces with their own semantics.
HTTP DELETE is of the transfer of documents over a network domain. The fact that the implementation of your handler includes a SQL DELETE is completely irrelevant.
Relatively few resources allow the DELETE method -- its primary use is for remote authoring environments, where the user has some direction regarding its effect.
It is OK to use POST.

Related

Understanding where to put constraints validation for REST api service using Spring

I'm working on a REST api for a model having the following entities:
A Team cannot exists if it has no relationships with a Course and a Student. At the beginning, I created an endpoint for the teams (API/teams) for the CRUD operations. Now I ended up moving all the CRUD operations for the teams under the following URLs:
/API/courses/{courseId}/teams
The same has been done for Machine that cannot exists without any relationships with a Team and Student, so any CRUD operation should be done to the following:
/API/courses/{courseId}/teams/{teamId}/virtual-machines
This makes sense to me, since every time I need to perform an operation on a Machine I have to verify the constraint for which the Machine is owned by a Team related to a Course. For this reason, If I continued to perform any operation on URLs like /API/teams I should have requested the course and team ids to verify those contraints in the request body.
Having said this, my CourseController invokes a VirtualMachineService for all the operations on the Machine entity. What it seems odd to me is that each signature of every method in the VirtualMachineService need to have the course and the team id to verify the above constraints. This caused to have lots of duplicated code in every method.
Are my design choices correct?
The CourseController only have to invoke the methods of VirtualMachineService and to validate the parameters coming from the requests body.
Should those constraints validation be done inside the controller or inside the service?
Neither Configuration nor Model are entities. Entities are classes from the domain (real world representations related to project, if you will), not every class you use.
REST doesn't directly care about your entity model (meaning graph) but you should follow the guidelines for specifying REST endpoints which is
different endpoint for
/courses/... and /teams/... - don't mix these. Any constraints you would like to apply are applied at the backend and have nothing to do with endpoint definitions.
Validation guide https://www.baeldung.com/spring-mvc-custom-validator

Should I Nest Routes to Resources in Laravel?

This may be a little subjective, but I feel that best-practice must exist (or even good design when it comes to Laravel apps). Googling results in lots of things that are not to do with the actual points in this question.
Say I am building a web application that has teams, which may have projects, which may have documents.
Should I design the routing so that documents are within the path of the projects they belong to, which are then within the path of the teams they belong to, or keep things at a top level?
As far as I can tell, there are two ends to this spectrum that are worth discussing (other options are just the grey in-between):
Nesting
Example, Doc C is found at: /teams/team-a/projects/project-b/documents/doc-c
It is easy to do this, and in the routing file, I can use route groups to help keep the structure clean. I think it's more logical and perhaps more convenient for the user (they can work out URLs for themselves!). My concerns are that I am importing complexity into each page request:
in checking that the route has integrity (i.e., that doc-c does belong to project-b), and
that the user has authority to access each of the nested assets all the way through the route.
Should I be putting gates/policy checks for every resource at the beginning of each controller method, for every route parameter? Otherwise, where can this be abstracted?
And regarding route integrity, I've never seen examples testing for this - so is this not a common approach? If we don't verify route integrity, then a page could show mixed information by hacking the route (e.g.,/teams/team-a/projects/project-Z/documents/doc-c, would show info about project Z on doc-c's page).
Without Nesting
Example, Doc C is found at : /documents/doc-c
In this example, every asset would have its own base route, more like an API I guess.
No integrity checks required, and the controller would pre-determine the other assets shown to generate the view.
But is this UX good enough? The majority of websites I've seen do not do this.
This is an interesting question - as you mentioned, it may be a little subjective, but worth the discussion.
You touch on a few points, so I will attempt to address them separately.
Nesting vs Not nesting
First thing to clear up in my opinion is browser routes versus API routes. If you are providing an API - either internally to your app or externally to the public, I would avoid nested routes for a few reasons:
resource/id format is quite standard and expressive for API's
this makes it easier to document
this makes it easier for the consumer app to dynamically construct API requests
However, your question does seem to focus on the browser routes. In my opinion browser routes can and should be whatever reads nicely - the url, especially these days, can be considered as part of the UI. For example, you may go to settings (and I would expect to see /settings), from the settings page, if I were to go into the notifications settings section, I would expect to see /settings/notifications.
The routes act and assist with UX - they are almost a breadcrumb and should look as such.
So, I would definitely nest for browser routes, and would definitely not for APIs.
Route integrity
The real heart of your question I think is about the route integrity. I think regardless if you choose to nest or not you need to be checking your permissions with the assumption that someone is tampering with the urls - the same way you assume that the user has tampered with the form input.
Essentially your routes (nested or not) act as input, and you will need to validate that. Route level middleware is one approach, but is often too generic to solve anything complex so you may find it easier to tackle it with controller middleware (https://laravel.com/docs/5.7/controllers#controller-middleware).
So you may do something like:
public function __construct()
{
$this->middleware('auth');
$this->middleware('canViewProject')->only('show');
$this->middleware('canEditProject')->except('store');
}
Whether you use Gates, Policies or just plain old middleware will probably depend on the complexity of the project - but the above applies regardless - treat the urls as input and validate accordingly
I've spent the last year looking at this and refining it, and stumbled upon an elegant solution recently. Nesting can be done nicely, I'm sticking to resource controllers and dot-syntax for nested route resources.
In order to enforce the route validation, I am using something like the following. There is a good answer here, which suggests explicitly binding the models in question.
So with
Route::resource('posts.comments', 'CommentsController');
You'd use
Route::bind('comment', function ($comment, $route) {
return Comment::where('post_id', $route->parameter('post'))->findOrFail($comment);
});
This will automatically work everywhere. If required, you could test for the upstream parameter to be found, and only perform the test in those cases (e.g. to cater for routes where only a comment is specified).
So much work has been subsequently done on Laravel. My default response to this is "yes, use route nesting". I keep routes restful, using (nested) resource controllers wherever possible, and single-action controllers for the odd use case. Route scoping is even automatic now, if specified correctly.
This always has been a discussion between developers even the creators of Laravel have this argument, so what is the good practice?
Lately I've seen a tweet from Taylor Otwell saying that he has deprecated the
nested routes section from Laravel docs because he didn't prefer it, while when you open Laracasts you see Jeffrey is implementing this concept like /series/php-testing/episodes/hello-world.
As I told it's a quiet argument and when it comes to choices like that I always do what it feels good for me. So if I were you I wouldn't nest neither teams or projects but maybe I would nest projects/documents, I don't go for nesting always.
This might be a bit of a deviation from the original question, but I feel that Adam Wathan's Laracon US 2017 talk might be a useful resource for this discussion. (https://www.youtube.com/watch?v=MF0jFKvS4SI)
I am relatively new to development and therefore explore a lot of code bases on github. I always struggle to understand nested routes. So as a best practice I would prefer no-nesting to nesting.
Keeping stuff "CRUDY by design" as Adam calls it, one thing you achieve, imo, is simplification of route names. If I were to work in a group, that is a pattern I would prefer.
However, referring to the penultimate paragraph on your question, I struggle to understand why an integrity check is not needed.
I think you should makes use of Role concepts, Route grouping , Middleware concepts to build this app
For Role related things check https://github.com/spatie/laravel-permission , a good package
Eg:
Route::group(['middleware' => ['role:super-admin']], function () {
//
});
You can almost do any role, permission related things using above package.
Assume roles like project manager, developer.
Group your Routes based on roles & assign proper Middleware as you need.
For URL : /teams/team-a/projects/project-b/documents/doc-c
Check the Authenticated user has a role in team-a & project-b (You can check this in Middleware, Controller or custom Service provider anywhere as your need).
Also just check https://laravelvoyager.com/
Thanks

In Laravel, what is the advantage of single action controllers?

A topic about single action controllers is in the laravel documentation:
https://laravel.com/docs/5.5/controllers#single-action-controllers
My question is, what is the use case where you will use this controllers? How will you structure your controllers if you opt to use single action controllers for all your controllers?
Michale Dyrynda seems to sum up the pupose of Single Action Controllers in his blog: https://dyrynda.com.au/blog/single-action-controllers-in-laravel
Conclusion
Single action controllers are an effective way to wrap up simple functionality into clearly named classes.
They can be used in instances where you're not necessarily following a RESTful approach; be careful not to separate multiple actions for a single entity across multiple controllers.
Where you might have previously used a single controller for multiple static pages, you could consider separate named controllers for each static pages.
You can add other methods to this class, but they should be related to the single action this controller is responsible for.
He also states that, you should only use these when you only need a single action for an entity:
You may consider naming the controller ShowPost as a way of being explicit about the controller's intent but I'd suggest caution with this approach; if you start seeing ShowPost, EditPost, CreatePost, etc controllers creeping into your codebase, I'd reconsider the RESTful approach. More controllers never hurt anybody, but we should be smart about when this is done!
This is an intresting question and my answer is not related to laravel, but to the single vs multiple actions per controller.
I have found when trying to find the use case for a pattern that is new, is to ask the inverse questions, in this case, when is the use case of multiple actions per controller make sense?
The answer usualy comes to:
You have an object that has crud operations (because your using sql)
and its convenient to place all the stuff related to that object in
one spot.
This is akin to the answer of "I have a hammer, so everything is a screw" and IF your domain is as simple as a thin layer over a crud database, then that is the use case for multiple actions per controller.
What I have found is that any amount of complexity blows up the controllers, no matter how good your model is. The reason is CRUD opperations are apart of your model, not your controller.
We usually think that we will map nicely to a CRUD model in our controller, there are many front end frameworks that work amazing at that, untill....
Look at the most common aspect of applications, users. In the setup your going to have index of users, which I don't know who would look at that page besides admins, and they usualy want extra information. so for the index action, you need admin custom authentication.
Then creation, well, it does not make sense to have an user create an user, you need to ensure the user is not authentication.
Now we talk about reading. What data an admin, other users, current user, and anon user can see is massivily differnt, and will slowly build up in complexity.
Then delete, this is normally rare action, and on some models not needed, but you still put it up, because, well you have a hammer.
The update, do you put password updates in here too? what if the user forgot there password? do you put that in here? No, you make a new action called forgot password.
Well now you need update password action. What goes in the update is usually a gigantic mess of hell after a year.
Each pattern has its pros and cons, my general advice is to do multiple actions per controller when your system is trully CRUD OR you will not have to maintain the project for more than a year. If you have any amount of complexity that will have to maintained, avoid the model leaking into the controller and keep them seperate.

what exactly is a RESTful resource web api? [duplicate]

Dumb question but I have some lingering confusion of what, exactly, a "resource" is in Rails. The term is used everywhere but I get a funny feeling it might be being used rather loosely. It's referenced in the model, the controller and, quite literally, in routes.rb.
Is it the specific route? For example, map.resources maps the 7 RESTful "resources". So an example of one resource would be the call to, say, the index action of a particular class's controller?!?
Is it a reference to the whole page/object being retrieved? or perhaps, more narrowly, a database table? or the row being retreived?
Is it something else?
Anyway, hopefully someone can set me straight...
Any object that you want users to be able to access via URI and perform CRUD (or some subset thereof) operations on can be thought of as a resource. In the Rails sense, it is generally a database table which is represented by a model, and acted on through a controller.
For example, you might have a User resource (with a users table in your DB). This is represented by a User model, is mapped to users_controller with map.resources :users (which then generates routes like /users (a collection of User resources) and /users/1 (a specific User resource).
You act upon those resources by using the appropriate HTTP method when making calls to those resources. POST to the resource collection (/users) creates a new record; GET retrieves a list of resources (/users) or a specific user (/users/1). PUT updates a specific user (/users/1/), and DELETE destroys that user. The URLs are the same, but the result (and controller action) may be different based on the HTTP verb. The idea, though is that /users/1 always means "I'm interacting with the User that has ID #1", regardless of the action.
Here's a good article discussing how most developers think that "Resource" is synonomous with the database table, the argument, I guess, being that mapping to the resource is mapping the controller to that database table (or, with ActiveResource, to another REST url).
Basically, I think a "resource" is "persisted data." map.resources maps the 7 RESTful actions to a particular suite of persisted data.
But I haven't thought about it too much in depth. Good question!
I think they probably mean it in the general web sense, i.e., Resource (Web):
the referent of any Uniform Resource Identifier
I don't think it has anything to do with database tables.
open your model folder, that is a hint of what resources you have!
example: users, pictures, comments...
A lot of people here say that resources refer to the database tables you have. It might be true sometimes but not necessarily true always. I could give you a lot of examples where you don't have a corresponding table in your database for a particular resource. Hence asssociating it with tables is rather wrong.
I would define a resource as a route which maps to related requests. So instead of declaring separate routes for the actions you want to do you can simply declare them using a resourceful route.In Rails, a resourceful route provides a mapping between HTTP requests and URLs to controller actions.
So say you define resources :users in config/routes.rb. You can now use a number of helpers to the controllers in your application like edit_user_path which returns users/edit .
Here's a good link: https://api.rubyonrails.org/v5.2.1/classes/ActionDispatch/Routing/Mapper/Resources.html
Which basically says: Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. Instead of declaring separate routes for your index, show, new, edit, create, update and destroy actions, a resourceful route declares them in a single line of code:
resources :photos

Generating Navigation for different user types, MVC, PHP

I have this idea of generating an array of user-links that will depend on user-roles.
The user can be a student or an admin.
What I have in mind is use a foreach loop to generate a list of links that is only available for certain users.
My problem is, I created a helper class called Navigation, but I am so certain that I MUST NOT hard-code the links in there, instead I want that helper class to just read an object sent from somewhere, and then will return the desired navigation array to a page.
Follow up questions, where do you think should i keep the links that will only be available for students, for admins. Should i just keep them in a text-file?
or if it is possible to create a controller that passes an array of links, for example
a method in nav_controller class -> studentLinks(){} that will send an array of links to the helper class, the the helper class will then send it to the view..
Sorry if I'm quite crazy at explaining. Do you have any related resources?
From your description it seems that you are building some education-related system. It would make sense to create implementation in such way, that you can later expand the project. Seems reasonable to expect addition of "lectors" as a role later.
Then again .. I am not sure how extensive your knowledge about MVC design pattern is.
That said, in this situation I would consider two ways to solve this:
View requests current user's status from model layer and, based on the response, requests additional data. Then view uses either admin or user templates and creates the response.
You can either hardcode the specific navigation items in the templates, from which you build the response, or the lit of available navigation items can be a part of the additional information that you requested from model layer.
The downside for this method is, that every time you need, when you need to add another group, you will have to rewrite some (if not all) view classes.
Wrap the structures from model layer in a containment object (the basis of implementation available in this post), which would let you restrict, what data is returned.
When using this approach, the views aways request all the available information from model layer, but some of it will return null, in which case the template would not be applied. To implement this, the list of available navigation items would have to be provided by model layer.
P.S. As you might have noticed from this description, view is not a template and model is not a class.
It really depends on what you're already using and the scale of your project. If you're using a db - stick it there. If you're using xml/json/yaml/whatever - store it in a file with corresponding format. If you have neither - hardcode it. What I mean - avoid using multiple technologies to store data. Also, if the links won't be updated frequently and the users won't be able to customize them I'd hardcode them. There's no point in creating something very complex for the sake of dynamics if the app will be mostly static.
Note that this question doesn't quite fit in stackoverflow. programmers.stackexchange.com would probably be a better fit

Resources