Jump to: navigation, search

OpenStack-SDK-PHP/JSON-schema-business-logic

How does JSON schema define business logic?

The simple answer is that they don't. JSON schemas only ever care about the data structures that exist on an API - it doesn't concern itself with HTTP requests, responses or exceptions. All it cares about is modeling domain resources in an interoperable language.

So, in terms of our SDK, what I'm proposing is actually a combination. We should use JSON schemas for modeling data, and a similar schema-like syntax for defining business logic. We could keep this custom syntax in JSON, or even define it in PHP so it can be opcode cached.

So how can it be done well?

A great example of how it can be done well is Google's Discovery API. They manage to blend all these different aspects (schemas/data structures, HTTP operations) of defining services into one coherent structure - I'd like to do a similar thing with our SDK. Other examples which are partially similar, but not as influential as the Discovery API, are Guzzle's custom DSL layer and Swagger.

Let's take an example. Say we're defining a POST operation that provisions a new server. In order for it to happen, a request needs to be serialized from some kind of service definition. A HTTP request is defined in the following manner:

  • A URL path is defined for the operation. Variables can be included (like an ID) too. In this case it would be "servers"
  • A HTTP method is defined; which, in this case, would be "POST"
  • A human-readable description of what the operation does
  • A response data structure is defined. This is done by referencing the schema. So for a "Create Server" operation, we know that the data returned should match the "Server" schema. Similarly, the "Get Server" operation should also return data that matches the "Server" schema. Think of schemas as blueprints that API data has to match.
  • Parameters are also defined with optional validation. So for the "Create Server" operation, the API expects: name, imageRef, flavorRef, networks. Each one needs to be defined.

Here's an example of what our schema file might look like.

Other useful features

  • Validating user values. This is extremely useful because catching erroneous user inputs minimizes unneeded HTTP calls. For example, you can enforce a parameter's type, only allowing a "string" to be sent for the server's name. In weakly-typed PHP code, you'd have to do this through conditional logic and clumsy type-checking; with schema you do it in one line because the logic's already there.
  • You also have additional, fine-grained validation controls over each data type:
    • strings: is there a min/max character limit? Should it satisfy a regular expression?
    • numeric: does it need to be lower or greater than a limit? Should it be a multiple of something?
    • arrays: should the array have a min/max count? Should each array item abide by a pattern? Should it be a unique array?
    • objects: should the object have a min/max count? Are there any required properties?
  • Aliases. For example, instead of asking the user to specify "flavorRef" we can use "flavorId" instead since it's more semantic. Aliases also come in useful for ugly extension namespaces ("powerState" instead of "OS-EXT-STS:power_state" for example).
  • Expected exceptions. So if a 404 is returned to the "Get Object" operation, we can use a custom exception class and a custom message to present to the end-user by just defining it. No extra code required.


The difference between user land code and a Google-Discovery-like schema DSL is that all of the above is readily available to help you expressively define the API contract. You don't need to write boilerplate, you don't need to write tests: everything has already been provided because it's baked into the library. What this means is that you're rolling out new features incredibly quickly.