RESTful api and related resources - php

I'm developing my first RESTful api, which (unfortunately) is being done on an already existing system and the idea is to allow third-parties to access this system.
Everything was fine until I realised that I have multiple ways to access the same resources. I will try to explain it using one of the parts of the system. The system has been built using Laravel 5.8 and has, among others, the following database tables:
users
emails
sms
Each user can have many emails, and each email belongs to only one user. The same applies for text messages.
I've "ignored" all the current code, because it wasn't built on a proper way to make it an RESTful api, so I've created a new folder Api and all my code is there.
I thought it would make sense to have the following endpoints
/api/v1/users
/api/v1/users/1
/api/v1/users/1/emails
/api/v1/users/1/emails/1
/api/v1/users/1/sms
/api/v1/users/1/sms/1
In this way I can have a list of users, get all the details of a user, get a list of emails/text messages and also get all the details of a specific email/text message. However, one of the requirements is to have a page with a list of emails/text messages, so it's starting to make sense to have:
/api/v1/emails
/api/v1/emails/1
/api/v1/sms
/api/v1/sms/1
To avoid having 2 endpoints to get the same resource (/api/v1/users/1/emails/1 and /api/v1/emails/1 will return the email with id 1) I'm considering to get rid of the deep endpoints /api/v1/users/1/emails and change them to something like /api/v1/emails?user_id=1.
Is this against RESTful principles? I couldn't reach a conclusion on my research about having 2 endpoints to access the same resource, but it doesn't "feel" right. On the other hand, having /api/v1/emails?user_id=1 may rise some security/privacy concerns (for example, I need to make sure that user 1 can only access /api/v1/emails?user_id=1 and not /api/v1/emails?user_id=2), but seems more flexible because I can use it alone to get all the resources or with the user_id filter to get only specific resources.
Is there a convention for this case?

It may help to review how we understand "resources" in a REST context.
Any information that can be named can be a resource: a document or image, a temporal service (e.g. "today's weather in Los Angeles"), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author's hypertext reference must fit within the definition of a resource.
/api/v1/users/1/emails
/api/v1/emails?user_id=1
/66eb6757-254e-49b4-bc8a-d04330f4482e
REST treats identifiers as semantically opaque -- general purpose clients do not use the spelling of the identifier to understand what is going on. Consider a web browser - it knows that http://example.org/cat.jpg is an image not because jpg, but because img.
That means that the server may use any spelling it likes -- any information encoded into the URI itself is done at the server's discretion and for its own use.
This isn't to say that there aren't advantages to using "guessable" spellings; just that REST is completely agnostic about whether or not identifiers should be guessable.
Choosing spellings for your identifiers that make your implementation simpler is completely within bounds.

Related

MVC + REST + nested resources + single page app

I'm a novice, but struggling hard to implement this interactive application I'm working on "the right way" or at least a good way in terms of scalability, maintainability, modularity, development speed and tool independence. That's why I chose the REST design guides and a framework which implements MVC.
However I can't get my head around where to put what in the following situation and any input or reading material from a more experienced developer in this techniques would be greatly appreciated :
I'm developing a single page web app which creates a resource that has several nested resources within. In the create methods and alike, I need to call the create methods from the nested resources. Right now every GET request is responded with a JSON, which the front end then parses, shows and add dynamically to the page accordingly. The question is : where should this create and store methods from nested resources be, in the controller or in the model?
Currently, my approach is : since the controller function is to handle user input, interact with model and return the view accordingly, the nested store methods are in the model since they're not created independently, their create methods are in the controller since they're requested from ajax calls, but this isn't nested, and so on. I'm worried that this is too mixed up and not general.
Am I ok ? Am I mixed up? I don't wanna make a mess for my coworkers to understand. Theory becomes tricky when applied..
I'm gonna have a go at this. I am myself still learning about this as well, so if any information is wrong, please correct me.
In terms of scalability, you should always be able to create any model independently, even though at this point it appears not strictly necessary. The REST paradigm stands for exactly this: Each model (a.k.a. resource) has its own (sub)set of CRUD endpoints, which a client application can use to perform any action, on any composition of data (compositions in which elementary entities are mostly the models you specify).
Furthermore, a model should be concerned with its own data only, and that data is typically found in a single table (in the case of relational datastores). In many cases models specify facilities to read related resources, so that this data can be included when requested. That might look like the line below, and the response is ideally fully compliant with the JSON API specification:
GET //api/my-resources/1?include=related-resource
However, a model should never create (POST), update (PUT) or delete (DELETE) these relations, not at all without explicit instructions to do so.
If you have a procedure where a model and its nested models (I assume related models) are to be created in a single go, an extra endpoint can be created for this action. You'd have to come up with a sensible name for that set of resources, and use that throughout your application's HTTP/support layer.For instance, for creation of such a set, the request might be:
POST //api/sensible-name { your: 'data' }
Keep the { your: 'data' }
part as close to a typical JSON API format as possible, preferably fully compliant. Then, in your back-end (I suppose Laravel, inn your case) you'd want to create a factory implementation that might be called <SensibleName>Factory that takes care of figuring out how to map the posted data to different models, and how their relations should be specified. Under the hood, this factory just uses the model classes' creation facilities to get you where you want to go.
When you would instead automate this process in your model it would be impossible to create the resources independently.
When you would instead automate this process in any single-resource controller that would be non-compliant with the REST paradigm.
With the factory pattern, you explicitly use that class to perform the higher level action, and none of the above concerns apply, not speaking about whether this approach is in accordance with REST at all.
The key takeaway is that the exact same result must still be achievable by performing multiple requests to single-resource endpoints, and your additional /api/sensible-name endpoint just substitutes for the need to call to those multiple endpoints, for the purpose of convenience, when you DO want to create multiple records in a single go.
Note that my statement has little to do with what endpoints to create to fetch nested resources. This SO question has some pretty good conversation as to what is acceptable, and how your specific needs might relate to that.
In the end, it's all about what works for you and your application, and REST and the like are just philosophies that propose to you an approach for similar needs in general web development as well as possible.

DDD and blameable

How do you handle situation with blameable in the DDD way?
Ofcourse we can ignore some things, but i think that when entity need some tracking (creator, updater, time updated / created) it should be in the class that actually performs some actions on entity.
For example we have post and user, what whould be the correct way?
$post = new Post();
$post->create(); // here we can set some created_id and
other attributes by using mixins or traits like some fw do
Or it is better like this:
$user->createPost($post);
$user->update($post);
As for me second is better, even when we need to track changes that does not apply to post directly, for example:
$post->doSomethingWithPost();
$user->updatePost($post);
Seems like blameable just throws out one important entity - user who manages some things on entities.
Ofcourse we should not overcomplicate things, but usually when blameable is implemented, entity from which you will get id is a logged in user, that is incorrect to the bounded context.
Here it is some Blogging Context, where user of this context updates post and not some authenticated user.
Whats your thoughts on this one? Is there some similar questions that i maybe missed?
All your examples seem like they are not designed with the DDD principles in mind. The first indicator to me is the usage of a $user variable. In 99% of the cases this is too generic to really capture the intent of a given Model. I think there are hidden concepts that would first have to be made explicit. I think along the lines of RegisteredAuthor and Administrator. At least that's what I understand from:
Here it is some Blogging Context, where user of this context updates post and not some authenticated user.
Another question is how can a "user of this context" not be authenticated? How do you know who he is?
In general in an application that explicitly requires User management we normally have something like an IdentityContext as a supporting Sub Domain. In the different contexts we then have other Models like Author or BlogAdministrator holding a reference to the User's identity (UserId) from the IdentityContext. The Red Book has some nice examples on how to implement this.
To answer the question on how to track who changed something and when:
This concept is also referred to as Auditability, which in most revenue relevant parts of system is actually a must once your organization is reaching a certain size. In this scenario I actually always recommend an Event Sourcing approach since it comes with auditability batteries included.
In your case it would actually be enough to either capture the executing UserId as Metadata to the commands like WritePostCommand or ChangePostContentsCommand or use the UserId in a RequestContext object that knows about the execution context (who was sending this command, when was it sent, is this user allowed to execute this use case).
You can then, as Alexander Langer pointed out in the comments, just use this metadata inside your Repositories or Handlers to pass the information to the Aggregates that need it, or could even just send them to an audit log to not pollute your Domain Model with this responsibilities.
NOTE: Generally I would not use the DoctrineExtensions like Blameable in your Domain Model. They depend heavily on Doctrine's Event system, and you do not want to tie your Model into an Infrastructure concern.
Kind regards

domain driven design proxy, cheating?

I am quite new to DDD and have some fundamental problems that i cant really understand.
Consider we have a User entity. A User has some Friend's (one to Many).
There are 2 possible solutions to fetch the friends.
Solution 1:
user.getFriends()
The Problem here is that all the friends have to be loaded or I am forced to use a Proxy.
If i use a Proxy it feels for me like cheating because the entity must not have an instance of the Repository. Can the Proxy have one?
Solution 2:
Avoid the getFriends Method and load the Friends Based on the User Repository, like:
userRepository.getFriendsOf(user)
This could sometimes be a good idea, but where to stop here? Whats about an AddressRepository for accessing user Addresses, or ?
I think you should look at it from perspective of Aggregate Roots.
In case of user.getFriends() - the user seem to be AR with associated friends which I don't think is correct. The definition of AR says "that we treat as a unit for the purpose of data changes". Friends are outside of the Boundary of user AR.
Considering the above the other option seem better - userRepository.getFriendsOf(user)
I'm not sure that either of them are correct. I think from a DDD point of view, the code is supposed to use the Ubiquitous Language of the domain. In that regard, getters are frowned upon.
Why are you getting the friends of a user? The public methods of User should reflect the ubiquitous language.
For example if your domain is a social networking site, users should have methods to update status which will internally notify friends etc. How the User knows who its friends are or how they are queried is hidden as an implementation detail.
One thing to keep in mind is that you shouldn't use your domain model for querying. So you do not want to be lazy-loading or applying any other fetching strategies.
You also need to identity your aggregates. An aggregate is loaded in its entirety from the data store.
In your case if a Friend class can only ever exist in the context of a User then it is part and parcel of the User and its life-cycle is linked to that of the User. That means that when the User is deleted (conceptually, as one probably would not want a hard delete) then the associated Friend instances are deleted also.
So if a Friend represent the association between users then it probably only contains the User Id. So you could go with a list of Ids in that case. This would depend on your domain.
I would guess that you very rarely would need to load the entire list of User instances that are friends of another user. If you need related data you could implement a light-weight query layer.

Symfony: REST web-service for bots and humans - open questions

I'm adding an API to a Symfony-application which should act as a REST web-service. But there are a few open issues.
Different URIs for bots?
I often read the "suggestion" to use URIs like /api/:id/[...], but I think they wouldn't be REST-compliant: No matter whether bot or human - the same unique resource is identified.
I'm asking, since my statement above makes sense, but I don't expect all the others to be at fault.
Modifying existing controllers?
There are several reasons why I need a separate controller-logic for both cases:
No session-login in the case of a api-requests
different Symfony-forms have to be created (For instance, no widgets are required, at all.)
JSON / XML instead of HTML output
I don't want to modify existing controllers. According to the Open-Closed Principle, classes should be open for extension but closed for modifications, and the controller classes are already in use in a "production"-environment.
My idea is to use an extra HTTP header-field (e.g. "X-UseApi"). The routing should call different actions by evaluating it. Is this possible inside routing.yml? How? Do you have other ideas?
Authentication
This is how I implemented bot-authentication:
$user = Doctrine_Core::getTable('sfGuardUser')->findOneByUsername($params['user']);
if($user->checkPassword($params['password']))
{
//...
}
But the code looks like a workaround to my eyes. Are there better solutions for the whole REST authentication issue? Is the sfGuardPlugin / sfDoctrineGuardPlugin not meeting conditions for such use cases?
Thanks in advance and cheers,
fishbone
my way of doing this would be to use sf_format in routes to distinguish between robot and human (robot will probably need to consume XML whereas human will want HTML.
I would alter my controllers in a way that I would delegate the logic to separate classes depending on what format is requested (this shouldn't be too much work and you would get the flexibility you need).
As for authentication - please provide a bit more information on how do you do it now - the example isn't enough for me to get the general idea of how your implementation works.
Different URIs for bots?
I suggest to not worry too much about URIs. There are more problems with them and thinking too much about it just results in losing time. IMHO it would be great if there would be standardized conventions how to define RESTful URIs. Here is an article about it: http://redrata.com/restful-uri-design/ . You can see that every way of designing your uris has its pros and cons.
But today I would reject the statement that 'api/...' isn't REST compliant. I would just avoid it.
Controller and authentication
Finally, my solution was to implement some sfFilters with responsibilities as follows:
ApiAccessFilter: sets request-attribute 'isApiRequest' if X-ApiKey is defined as header field.
ApiKeyAuthFilter: identifies a user by X-ApiKey, calls signIn / forwards to login-action.
SecureApiAccessFilter: Checks whether the current user has credential
'apiWriteAccess', if HTTP-method is POST, PUT or DELETE.
The first filter allows me to call $request->getAttribute('isApiRequest') later in my actions. That's similar to isXmlHttpRequest(). Finally I came to the conclusion that I have to modify existing actions, because requirements have changed due to the web-service extension.
Cheers, fishbone

Does php mvc framework agavi use CRUD compliant to REST?

The agavi framework uses the PUT request for create and POST for updating information. Usually in REST this is used the other way around (often referring to POST adding information while PUT replacing the whole data record).
If I understand it correctly, the important issue is that PUT must be idempotent, while POST does not have this requirement. Therefore, I wounder how creating a new record can be idempotent (i.e. multiple request do not lead to multiple creations of a record) in particular when usually the ORM uses an id as a primary key and the id of a new record would not be known to the client (since it is autocreated in the database), hence cannot be part of the request. How does agavi maintain the requirement of idempotence in light of this for the PUT request.
Thanks.
PUT can be used both for creation and for updating complete records. POST is usually used for partial updates and related operations as well as for creating a new type of record on the server without specifying a URL for the resource (e.g. POST to /articles/23/comments returns a 201 status and a Location: /articles/23/comments/283136 header). So in your case (with a sequence/autoincrement ID), you would use that approach.
However, HTML (and thus web forms) is different. It only knows GET and POST, not DELETE and PUT. For deletion and updating operations, it overloads the POST method.
That's why Agavi, by default, maps POST to "write" and GET to "read" - it's the most common use case, and "read" and "write" were chosen because they are relatively neutral and also in a way represent the safety aspects of GET vs POST (safety as in "GET can be called without side effects" and blah).
You can change the mapping of verbs for the AgaviWebRequest implementation in factories.xml; refer to the Agavi users mailing list or the IRC channel if you need help with that (or ask away here). A lot of people on the IRC channel are also quite experienced with URL scheme design in case you need more help with making your API pretty.
Instead of thinking of PUT as creating, think of it as "putting". You put a resource at a URI (ie send an entire resource to a URI).
PUT http://example.com/articles/1
If you repeat this (send the same entire resource to the same URI) you get the same result and you haven't changed the resource at that URI, that's what makes it idempotent.
If agavi's implementation of PUT is idempotent then it is implementing PUT correctly. Otherwise it's not.
PUT can be used to create a resource, except that if the resource already exists (or has already been created by a previous PUT) it will just update it. POST should not update resources, however, if this is simple CRUD. Note that the HTTP verbs do not have a defined mapping to certain actions necessarily, since they're useful for a lot more than just CRUD.
Also note that this question has nothing to do with REST - just proper HTTP usage. So please remove the REST tag.
I've had this problem before. This can be solved by changing the factories.xml

Categories