HEY - ANOTHER MESSAGE. AND GUESS WHAT?

You were right. This website uses cookies, and we are obliged to inform you about:

1. technically necessary cookies, e.g. to make the grav cms work or to enable disqus
2. "evil" tracking cookies from Google Analytics (IPs anonymized, of course) sometimes combined with "Optimize A/B Testing", so that we can adapt our website to your needs

This blog post will give an introduction to the appserver.io implementation of techniques such as Design by Contract and AOP and how they can be used.
As an example we will make a simple and self validating JSON REST webservice.

Our webservice in question exposes a basic CRUD like JSON API and can be used to store object representations of user accounts.
What we will focus on is the handling of invalid data and how to respond to malformed requests without much (nearly none) effort from the developer side.

appserver.io utilizes the appserver-io/doppelgaenger library and allows to use its functionality within any webapp using annotations and XML configuration.
This example makes use of this as a showcase example to further expand on.

How it works

To make our API self validation we have to meet two requirements:

We have to define valid/invalid states and transitions

We have to define a reaction to both

Defining valid/invalid states

To define how our API is used in a valid or invalid way we will make use of the Design by Contract (DbC for short) feature of appserver.io.
Using it can be done by placing well designed constraints into our applications.
These constraints define so called contracts, doublets of pre- and post-condition and a coherent state, the invariant, which marks the valid state and transitions our app
can handle.

You can define these contracts using Doctrine-like annotations containing valid PHP code conditions resulting in the boolean TRUE or FALSE.

Any breach of a contract will result in an exception of the type AppserverIo\Psr\MetaobjectProtocol\Dbc\ContractExceptionInterface which we can later handle centrally.

Preconditions can be annotated using the @Requires annotation, whereas post-conditions are defined using the @Ensures annotation.

So to explain how we use these concepts, we will have to have a look at the flow of data through our application.

If a request hits any of the actions we defined (more on that later) the request content will be passed to a connector class (JSON in our example) which tries to extract the needed information from the request message.
So basically turning JSON into objects of a certain type.

But as we do so, we want to also validate every step on the way.
Have a look how we do it:

It is implemented within the abstract \AppserverIo\Apps\ApiGuard\Actions\AbstractCrudAction class and as inherited by the UsersAction class, results in the URL http://127.0.0.1:9080/api-guard/index.do/users/create being exposed to GET and POST requests.

The body-less method allActionMethods acting as a pointcut specifying all action methods in all action classes

The method actionExceptionToError action as Around advice handling the exception

First things first, the pointcut:

Pointcuts are used to specify certain events at certain places within your applications flow.

The annotation @Pointcut("call(\AppserverIo\Apps\ApiGuard\Actions\*->*Action())") allows us to have a code hook at every call to every action method of every action class we have.
Let me repeat that: every call to every action method of every action class we have! :)

The advice references the pointcut using the annotation @Around("pointcut(allActionMethods())") and wraps around (hence the name Around) all specified methods.
That allows us to catch every DbC exception within any action and handle it in a central way.

Using the automatically passed $methodInvocation instance we are able to access the action instance in question and therefore using the connector to append an automatic response.

Tadaa: Automatic validation of client requests using annotations!

Try it yourself!

Got a taste for AOP? Build a contracted API yourself?
Have a look at the api-guard app which contains all examples and the working code to build your own webservice.

To do this, we assume you have installed appserver.io in a version of at least 1.0.0-rc3.

You also need the sources of this repository. So clone it, open a command line, change into your
working directory, which can be /tmp for example, and enter:

$ git clone https://github.com/appserver-io-apps/api-guard

Now you can change into the newly created api-guard directory and use our ant app deployment by executing:

$ ant composer-init
$ ant deploy

Testing it

You can test the example's guarding functionality using simple CURL commands.
Using our default example of the User entity you might try the following:

will return a response status 200 as all constraints were met and a JSON representation of the user entity was stored in our Singleton Session Bean
(yes, this is a built-in in-memory data storage).

A final note

The discussed techniques allow for a pretty powerful validation mechanism but there are still things we will expand on.
Next thing on our roadmap will be a better mapping of exceptions, allowing for more specific response messages!