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

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

Related

What is the best practice for using services in Symfony instead of Controllers and not only there?

Well i'm learning Symfony (3.3) and i'm little confused about Service Container. In first tutorial the lector show register, login, add post, edit, delete methods in User, Article Controllers. Then in other tutorial, they show same methods but use Service Container (User and Article services) with User and Article interfaces. So .. what is the best practice for implementation in Services instead of Controllers.
I would like to add to Alexandre's answer that it is considered best practice to keep your controller 'thin'. In other words, only put code in your controller that really has to be there (or if it only makes sense to put it in your controller).
Services are like tools you can use in your application. A service in an object that helps you do something. In one service, you can have many functions. I think the best way to understand the difference is that a controller is for one specific action, a service can be used in many actions. So if you have parts of code that you want to use in more than one controller, create a service for it. And for the sake of re-usability, create functions in your service that do only one thing. This makes it easier along the way to use these functions.
the "best practise" depends on what you want to do with the Service. If you build an REST-Api you might want to do Database-Operations in Controller. Why? When you rely on the SOLID-Pattern you want to reduce or eliminate redundant code. If you code a real REST Api you don't have redundant code because each REST-Verb will do a different query/thing.
So in a non-REST-Api-application you will have a lot of redundant code. You do the same things/services on different pages/controller-actions. So the best thing is to implement all the business-logic in services to have it only one time in one place. If you have a lot of individual queries place them into repositories. If you have business-logic that fit's into an entity-class place them there. So in my opinion you can choose a thick controller/no service design in API's and a thin controller/thick service design in classic symfony front-/backend applications.
But one more thing: there is no totally wrong way to design an application. But if you work with other people or want to run the application longer than a month (without having trouble to maintain it) you should pick a common design-pattern.
Controller must implement the application logic like check if it's a post request or if a form is submit etc...
Never use DQL or any SQL Request directly inside a controller !
EDIT In the example i use a find method inside the controller because it's a Repository method but i parse the result inside slugify (my service method)
Services contains business logic like formatting phone numbers, parse some data etc...
Of course you can inject a repository inside a service and call your methods inside it.
An example:
//This is a fictive example
public function indexAction(Request $request) {
//Application logic
if(!$request->get('id')) {
//redirect somewhere by example
}
$article = $this->getDoctrine()
->getRepository(Article::class)
->find($request->get('id'));
//Business Logic
$slug = $this->get('my.acme.service')->slugify($article->getTitle());
}
Hope this helps

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

How to route a url in PHP?

I'm trying to implement url routes into my own mvc framework and I like to find out the best way to do it. I'm thinking three solutions.
Make a XML file and read it in my frontend controller then load the matching controller.
Make a table that stores routes then execute a query in my frontend controller then load the matching controller.
use either xml or table and then load routes into memcache then use it.
my concern for #1 and #2 is that I have to read a table or xml for the every access.
my concern for #3 is that not all the hosting companies support memcache.
Any suggestions would be appreciated!
Added: I think I confused some people. By 'route', I'm actually talking about rewriting...like...I want to rewrite visitors to '/controller/action' when they visit '/hello'
Thanks
I would not use XML or tables for this. This will require additional resources for such (in comparison) easy operation. You should have a script which is loaded by mod_rewrite, it parses the URL, loads the proper controller and executes the action.
Hey I know this is a little late, but please check out my Routes class. I know you may not need it now, but hopefully it will still be useful to others.
With this you could easily do exactly what you need to with simple syntax and rules. All you need is to break down the parts of the returned URL (from a Routes::route() call) to calculate your controller and action method (and any possible parameters).
The reason this routing library doesn't do that for you is because you may not be in an MVC world when using it, but it's not that difficult to create. Because it's so low-level you could even create routes dynamically, say from a database table or memcache.
I think I can re-phase and even generalize the problem:
You want to create a representation for something (in this case URL
routes) that are easily human readable (eg, XML);
You might also like that this representation can be easily
computer-generated (eg, from a database table);
At run-time you don't want the solution to be slow: eg, parsing a
large XML file, reading from disk, or fetching rows from a database.
You don't know what caching solution will be available in a
production environment.
So you should aim to:
Perform the slow operations (reading from a database, parsing XML) as
little as possible - perhaps in a compile or build phase, or "on
first run".
Perform the route matching in a fast way: compile the rules directly
into PHP code, and execute them as regular expressions or some such.
Cache the rule code as a php file and include it as regular code. APC
is a php code cache that is commonly available in all production
environments.
This would lead me to implement a solution with the following classes and methods:
Router::addRoute(pattern, controller) - adds a route
Router::match(uri) - returns matching controller
You can store routes in whatever format you fancy (XML, Json, in a database), and generate a simple PHP include file to load routes quickly at runtime:
<?php
// compiled_routes.php
$router = new Router();
$router->addRoute('/', 'HomeController');
$router->addRoute('/widgets', 'WidgetsController');
tl;dr: separate the route rule-parsing from the route matching. Perform rule-parsing only once, and compile the result into PHP code which can be cached by APC.
Hope that helps.

How to create a RESTful API?

Over the last few weeks I've been learning about iOS development, which has naturally led me into the world of APIs. Now, searching around on the Internet, I've come to the conclusion that using the REST architecture is very much recommended, due to its supposed simplicity and ease of implementation.
However, I'm really struggling with the implementation side of REST. I understand the concept; using HTTP methods as verbs to describe the action of a request and responding with suitable response codes, and so on. It's just, I don't understand how to code it.
I don't get how I map a URI to an object. I understand that a GET request for domain.com/api/user/address?user_id=999 would return the address of user 999 - but I don't understand where or how that mapping from /user/address to some method that queries a database has taken place.
Is this all coded in one PHP script? Would I just have a method that grabs the URI like so:
$array = explode("/", ltrim(rtrim($_SERVER['REQUEST_URI'], "/"), "/"))
And then cycle through that array, first I would have a request for a "user", so the PHP script would direct my request to the user object and then invoke the address method. Is that what actually happens?
The main thing I'm not getting is how that URI /user/address?id=999 somehow is broken down and executed - does it actually resolve to code?
class user(id) {
address() {
//get user address
}
}
Actually the API you're trying to describe now is not RESTful. There are many sources describing how to make RESTful APIs. So you should first define your API (taking in account how your client software would use it) and then implement it. I'm quite sure that almost any RESTful API can be implemented in PHP.
Here are some other tips on how to make a RESTful API.
In my opinion GlassFish Server REST Interface is a good example of RESTful design.
That's two questions.
To honor RESTful HTTP verbs, you have to query $_SERVER["REQUEST_METHOD"]. It will contain the usual GET or POST unless a more specialized HTTP request was received. The whole REST buzz is somewhat misleading in itself, and also in misusing the HTTP verbs just for routing.
Anyway, the mapping of request URLs to functions can be achieved in two ways. It's most reliable to use a static map, for example an array that lists URL patterns and destination methods. Most PHP frameworks use an implicit mapping like so:
$args = explode("/", trim($_SERVER['REQUEST_URI'], "/"));
$class = array_shift($args);
$method = array_shift($args);
call_user_func_array("$class::$method", $args);
Note how this is a bad example, security-wise. Only allowed and specifically prepared classes and methods should be able to receive requests. Most frameworks just check if it was derived from an acceptable base class after loading it from a known path and/or instantiating. But a static map is really preferable.
Anyway, regular expression mapping or handling by mod_rewrite is also common. And for utilizing HTTP verbs, just include it as method name.
Have a look at FRAPI - http://getfrapi.com/
As it says focus on your business logic, not presentation.

Categories