Best practice for custom REST actions with API Platform - api-platform.com

This top-ranking Stackoverflow answer from 10 years ago suggests using POST /users/:user_id/reset_password to initiate a password reset.
I know the API platform recommends against using custom operations. The docs page for the Symfony Messenger integration uses a ResetPasswordRequest entity (with a username field). That makes sense to me. 
Say I have a User and Notification entity and maybe a joined UserNotification (with a hasRead) entity as well. I want to expose an endpoint on my API to mark all the notifications older than a month as read. So I might make a ClearOldNotification entity, again with a username field.
Another example might be I want a report showing Customers that haven't been contacted due to some criteria. So I want to join the tables in the server and return a custom JSON data object. Again I could make a CustomerNoContact entity.
The issue I see is that I now have a distinction between pure entities, like a User or Product, as opposed to these service type entities.
Is this method of making individual entities classes for actions the recommended, best practice for Symfony and API Platform?
Should I be name-spacing (or something) these entities differently within my app to distinguish them?
I could imagine on a really large and complex application you could have hundreds of these service entities, compared to the pure entities. Is that expected or desired?
Can anyone recommend some good resources on this pattern?

You're asking for a best practice for two different use cases. Let's break it down:
ClearOldNotification
I think you've already found the solution: using Messenger. As you've read, there is an example in the documentation for this use case:
#[ApiResource(collectionOperations: [
"post", "get", "delete",
"reset_password" => ["status" => 202, "messenger" => "input", "input" => ResetPasswordRequest::class, "output" => false, "method" => "POST", "path" => "/users/reset_password"]
]
)]
final class User
{
}
The ResetPasswordRequest class is a Data Transfer Object (DTO). In your ResetPasswordRequestHandler you should inject the service that is responsible for resetting the password and sending an email.
CustomerNoContact
This could be a Custom (Doctrine ORM) Filter.

Related

Apollo Client: can apollo-link-rest resolve relations between endpoints?

The rest api that I have to use provides data over multiple endpoints. The objects in the results might have relations that are are not resolved directly by the api, it rather provides ids that point to the actual resource.
Example:
For simplicity's sake let's say a Person can own multiple Books.
Now the api/person/{i} endpoint returns this:
{ id: 1, name: "Phil", books: [1, 5, 17, 31] }
The api/book/{i} endpoint returns this (note that author might be a relation again):
{ id: 5, title: "SPRINT", author: 123 }
Is there any way I can teach the apollo client to resolve those endpoints in a way that I can write the following (or a similar) query:
query fetchBooksOfUser($id: ID) {
person (id: $id) {
name,
books {
title
}
}
}
I didn't try it (yet) in one query but sould be possible.
Read docs strating from this
At the beggining I would try with sth like:
query fetchBooksOfUser($id: ID) {
person (id: $id) #rest(type: "Person", path: "api/person/{args.id}") {
name,
books #rest(type: "Book", path: "api/book/{data.person.books.id}") {
id,
title
}
}
}
... but it probably won't work - probably it's not smart enough to work with arrays.
UPDATE: See note for similiar example but using one, common parent-resolved param. In your case we have partially resolved books as arrays of objects with id. I don't know how to use these ids to resolve missing fields () on the same 'tree' level.
Other possibility - make related subrequests/subqueries (someway) in Person type patcher. Should be possible.
Is this really needed to be one query? You can provide ids to child containers, each of them runing own query when needed.
UPDATE: Apollo will take care on batching (Not for REST, not for all graphql servers - read docs).
'it's handy' to construct one query but apollo will cache it normalizing response by types - data will be stored separately. Using one query keeps you within overfetching camp or template thinking (collect all possible data before one step rendering).
Ract thinking keeps your data and view decomposed, used when needed, more specialised etc.
<Person/> container will query for data needed to render itself and list of child-needed ids. Each <Book/> will query for own data using passed id.
As an alternative, you could set up your own GraphQL back-end as an intermediary between your front-end and the REST API you're planning to use.
It's fairly easy to implement REST APIs as data sources in GraphQL using Apollo Server and a package such as apollo-datasource-rest which is maintained by the authors behind Apollo Server.
It would also allow you to scale if you ever have to use other data sources (DBs, 3rd party APIs, etc.) and would give you full control about exactly what data your queries return.

Clean Architecture: How to reduce complexity when writing application business rules?

Let's assume we have the following "Create User" scenario:
Users can signup to the application using Facebook, Google+ or LinkedIn;
The backend should retrieve some basic profile information in order to register the user(email, firstName and lastName);
Users are registered with a "client Id" (Just adding complexity to the business rule);
When a signup process is done the data should be sent to a notification topic.
I can imagine a create user request with the following structure:
{
"clientId": "someClientId",
"authProvider": "FACEBOOK | GOOGLE | LINKEDIN",
"accessToken": "someAccessToken"
}
So, thinking about the registration/validation flow we would have:
Check if the create user request is valid;
Check if the clientId is valid;
Try to retrieve the profile information from the social network api;
Check if all the required profile information is filled;
Check if the user exists in the database;
Register the user;
Send the data to the notification topic;
Pass the data to the presenter.
Jumping straight to the use case, we would have a constructor like:
CreateUserUseCase(
ApplicationClientGateway applicationClientGateway,
SocialNetworkGateway socialNetworkGateway,
UserGateway userGateway,
NotificationGateway notificationGateway,
Presenter presenter
)
and an execute method:
execute(CreateUserRequest request)
// validates the payload
// something like
if (request == null)
presenter.setError(someError);
// validates the clientId
applicationClientGateway.findById(request.getClientId())
// retrieves the profile information
// how to inject dinamically the implementation for
// Facebook, Google or LinkeIn based on a request parameter?
profile = socialNetworkGateway.findByAccessToken(request.getAccessToken());
// checks if the user exists
userGateway.findByEmailAndAuthProvider(profile.getEmail(), request.getAuthProvider());
//register the user
userGateway.insert(user);
//sends the notification
notificationGateway.send(user);
// sets the result
presenter.setResult(user);
Now, we have a constructor with lots of arguments(code smells?) and at least 5 validation steps in the execute method.
It looks like a violation of the SRP, so, how can we decompose this code in order to reduce complexity in the interactor?
First of all, lets break this in some small steps:
1) Related to the presenter, looks like you are intersted in give the workflow some output, right? Assuming that, maybe it will be better to return what you want from the usecase and handle this one layer above. (-1 parameter at constructor)
2) Like the others answers are saying, looks like your usecase has a LOT of responsabilities right now. I will suggest you to break this in more then one usecase.
Something like:
... Your first gateway (API)
..... ValidateClientId.execute();
..... profile = RetrieveProfile.execute();
..... InsertUser.execute(...)
3.1) Related to inject the correct bean based on the correct social network, you can handle this logic INSIDE the gateway, not before call it. Remembet that one gateway CAN call another gateway (they are at same layer). So, I suggest you to use something like.
At usercase -> socialNetworkGateway.findByAccessToken(...)
Inside the gateway you can do your "switch" and call somthing like the FacebookGateway, GoogleGateway, etc.
SRP does not say that you have to have small methods or only few constructor parameters. SRP says "there should be only a single reason to change the code".
As far as I can see you explicitly implemented the "business logic sequence" required to register a new user. Even though this may require some "external services" and/or repositories there is still only one reason to change the logic of this code: if the logic "how to register a user" changes.
From this perspective you are not violating SRP.
According to Uncle Bobs picture on "control flow" (https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html) it is also totally correct to pass the presenter.
If you still feel the need to reduce the dependencies of your use case class I would suggest looking into "unit of work" pattern and check whether it would make sense to combine some of the dependencies.
More details on "What is a use case in Clean Architecture" you can find in my blog series: http://www.plainionist.net/Implementing-Clean-Architecture-UseCases/

Web application's form validation - design to propagate domain errors to client-side?

Data validation should occur at the following places in a web-application:
Client-side: browser. To speed up user error reporting
Server-side: controller. To check if user input is syntactically valid (no sql injections, for example, valid format for all passed in fields, all required fields are filled in etc.)
Server-side: model (domain layer). To check if user input is domain-wise valid (no duplicating usernames, account balance is not negative etc.)
I am currently a DDD fan, so I have UI and Domain layers separated in my applications.
I am also trying to follow the rule, that domain model should never contain an invalid data.
So, how do you design validation mechanism in your application so that validation errors, that take place in the domain, propagate properly to the client? For example, when domain model raises an exception about duplicate username, how to correctly bind that exception to the submitted form?
Some article, that inspired this question, can be found here: http://verraes.net/2015/02/form-command-model-validation/
I've seen no such mechanisms in web frameworks known to me. What first springs into my mind is to make domain model include the name of the field, causing exception, in the exception data and then in the UI layer provide a map between form data fields and model data fields to properly show the error in it's context for a user. Is this approach valid? It looks shaky... Are there some examples of better design?
Although not exactly the same question as this one, I think the answer is the same:
Encapsulate the validation logic into a reusable class. These classes are usually called specifications, validators or rules and are part of the domain.
Now you can use these specifications in both the model and the service layer.
If your UI uses the same technology as the model, you may also be able to use the specifications there (e.g. when using NodeJS on the server, you're able to write the specs in JS and use them in the browser, too).
Edit - additional information after the chat
Create fine-grained specifications, so that you are able to display appropriate error messages if a spec fails.
Don't make business rules or specifications aware of form fields.
Only create specs for business rules, not for basic input validation tasks (e.g. checking for null).
I want to share the approach used by us in one DDD project.
We created a BaseClass having fields ErrorId &
ErrorMessage.
Every DomainModel derive from this BaseClass & thus have a two extra fields ErrorId & ErrorMessage available from
BaseClass.
Whenever exception occurs we handle exception(Log in server, take appropriate steps for compensating logic & fetch User Friendly message from client location based localized Resource file for message ) then propagate data as simple flow without raising or throwing exception.
At client side check if ErrorMessage is not null then show error.
It's basic simple approach we followed from start of project.
If it's new project this is least complicated & efficient approach, but if you doing changes in big old project this might not help as changes are big.
For validation at each field level, use Validation Application Block from Enterprise Library.
It can be used as :
Decorate domain model properties with proper attributes like:
public class AttributeCustomer
{
[NotNullValidator(MessageTemplate = "Customer must have valid no")]
[StringLengthValidator(5, RangeBoundaryType.Inclusive,
5, RangeBoundaryType.Inclusive,
MessageTemplate = "Customer no must have {3} characters.")]
[RegexValidator("[A-Z]{2}[0-9]{3}",
MessageTemplate = "Customer no must be 2 capital letters and 3 numbers.")]
public string CustomerNo { get; set; }
}
Create validator instance like:
Validator<AttributeCustomer> cusValidator =
valFactory.CreateValidator<AttributeCustomer>();
Use object & do validation as :
customer.CustomerNo = "AB123";
customer.FirstName = "Brown";
customer.LastName = "Green";
customer.BirthDate = "1980-01-01";
customer.CustomerType = "VIP";
ValidationResults valResults = cusValidator.Validate(customer);
Check Validation results as:
if (valResults.IsValid)
{
MessageBox.Show("Customer information is valid");
}
else
{
foreach (ValidationResult item in valResults)
{
// Put your validation detection logic
}
}
Code example is taken from Microsoft Enterprise Library 5.0 - Introduction to Validation Block
This links will help to understand Validation Application Block:
http://www.codeproject.com/Articles/256355/Microsoft-Enterprise-Library-Introduction-to-V
https://msdn.microsoft.com/en-in/library/ff650131.aspx
https://msdn.microsoft.com/library/cc467894.aspx

How to set up raw_id_fields in django-rest-framework?

In Django admin, one can set up a raw_id_fields in order to have a search widget instead of a select box. This is very neat to spare up a lot of database queries when the foreign key table is huge.
What is the equivalent in the Django Rest Framework browsable views?
Django Rest Framework 3 no longer supports widget attribute on serializer field. But to get your browsable API even usable, try changing style attribute to use 'base_template': 'input.html' as in following example:
class CustomerAddressSerializer(serializers.ModelSerializer):
customer = serializers.IntegerField(source='customer_id' style={'base_template': 'input.html', 'placeholder': "Customer ID"})
class Meta:
model = models.CustomerAddress
fields = ('id', 'customer', 'street', 'zip', 'city')
This way your huge select tag with thousands foreign key options will change to simple text input. For more info check docs at http://www.django-rest-framework.org/topics/browsable-api/#handling-choicefield-with-large-numbers-of-items
There's nothing to support this currently. I'm pretty sure that pull requests would be welcomed.
Seconding what Carlton says, although it'd be worth discussing in a ticket prior to taking a stab at the implementation.
Alternatively, you might want to take a look at using an autocomplete widget...
http://www.django-rest-framework.org/topics/browsable-api/#autocomplete

How to set up FubuMVC validation

I'm trying to learn FubuMVC and have gotten stuck on validating my input models.
What I want to accomplish is post-validate-redirect. That is, to redirect to same view and show the errors if the model is invalid. I'm using attributes on my models.
Also, how would I specify my own error messages, i.e localization?
I'm using the latest packages of Fubu from nuget.
My registry looks like this:
IncludeDiagnostics(true);
Applies.ToThisAssembly();
Actions.IncludeClassesSuffixedWithController();
Routes
.HomeIs<HomeController>(x => x.Index())
.IgnoreControllerNamesEntirely()
.IgnoreMethodsNamed("Index")
.IgnoreMethodsNamed("Query")
.IgnoreMethodsNamed("Command")
.IgnoreNamespaceText("Features")
.IgnoreMethodSuffix("Html")
.RootAtAssemblyNamespace()
.ConstrainToHttpMethod(x => x.Method.Name.EndsWith("Command"), "POST")
.ConstrainToHttpMethod(x => x.Method.Name.EndsWith("Query"), "GET");
this.UseSpark();
this.Validation();
HtmlConvention<SampleHtmlConventions>();
Views.TryToAttachWithDefaultConventions();
The FubuMVC.Validation package is really just an example of how to use FubuValidation as we haven't built it out for all of the edge cases. Having said that, let me explain a little bit about how it works so we can see if you can use it, or if you should just handroll your own validation behavior.
The ValidationBehavior uses the IValidationFailureHandler interface to "handle" validation failures. The Notification object built up from FubuValidation is shoved into the IFubuRequest when the behavior fires, and then the handler is called.
The ValidationFailureHandler class is wired up by default for all
validation failures. This delegates to the IValidationFailurePolicy to
determine the strategy to use for a given model type (see my post on
policies for an explanation of how this works).
The Validation extension method has an overload which gives a micro-
dsl for configuring these policies:
this.Validation(x => {
x.Failures....
});
From here you can 1) apply custom policies via the ApplyPolicy method
or 2) use the predicate based configuration approach via the IfModel methods.
If you go the predicate route (e.g., x.Failures.IfModelIs()), you can tell FubuMVC.Validation to use FubuContinuations to redirect or transfer to another behavior
chain. Rex recently posted about FubuContinuations if you're looking for some guidance in this area (http://rexflex.net/2011/07/fubumvc-fubucontinuation/).
Hope this helps and feel free to ask away if I didn't explain anything enough,
Josh

Resources