Back end development best practices
This documentation talks about back-end development best practices for Jahia Modules.
This documentation focuses on the essential, it does not dictate you how to code, or which framework you should use. Instead it explains you how to organize your backend to make it easier to read, easier to evolve and easier to maintain.
It presents the differents APIs Jahia modules can provide, and the best type of APIs to implement depending on your needs.
Jahia Modules can do a lot of things and can be really complex, they are able to extends Jahia Core by providing Actions, Filters, Rules, Servlets, REST APIs, GraphQL APIs, Spring services, OSGI Services and lot of other type of Objects that will enrich the module complexity.
Service oriented back-end
Why should I provide a service layer in my module?
The first best-practice guideline is to: put your logic and objects manipulation inside dedicated service layer. This way you will be able to:
- unit tests the back end logic easily
- centralize your logics in one place
- leave you the choice of a potential API to interact with your logic.
Having a separation between the API ( what is exposed to be consumed by external calls ) and the Service layer allow you to design properly the service layer without any representation constraints. You can focus on the main logic itself, the first level of your application.
Example of bad practice, and how a service layer could ease the process:
- When you need to provide new API inside an existing one, the new API will potentially need the code already done previously in the API. You will either start to duplicate the code or externalize it in a dedicated place. This could be avoided by separating the service layer from the API layer at the beginning of the project.
- Imagine an Action that is responsible of a given business logic. You want to automate this business logic by using a Job and/or Rules, you will not be able to access the business logic from the Job or the Rules because it’s an Action. By extracting the responsible code inside a dedicated service layer you could use it from anywhere you want in your application.
There is a lot of example like this in real life.
It’s mainly due to the fact that it’s easy and fast to provide a module with an Action that do all the job. It’s faster than designing a service layer with interfaces, implementation and potentially other layer of abstraction within.
But the issues comes when your module start to get bigger and bigger and at the end contains a lot of Actions, static classes with static functions that doesn’t respect any interface, sharing code or duplicating code. It can become a nightmare when you need to access the logic from different places like:
- Other services from other modules
At a moment you will realize that the module code base is not maintainable anymore. At this step generally you imagine a big refactoring to clean the project, but it’s too late, rewriting the code base could cost a lot.
So the conclusion is:
Interfaces, are they mandatory in the service layer?
A best practice consist of using interfaces when designing the service layer, they are recommended in backend service layer. They impose to you the responsibility of respecting a contract between the service layer and the API layer(s).
Also interface help to read the logic of a given service, by looking at it you have the list of all the contracts and signatures, each of the methods should be documented with JavaDoc.
In the OSGI world of Jahia module, the interfaces also help you to expose your service layer to the other modules. In such case they are mandatory.
Special mention for OSGI Services: its recommended to separate the interfaces and the implementation(s) in different bundles, by doing so you will be able to change dynamically the implementation.
API layers in Jahia modules
Like mentioned previously there is multiple type of possible APIs, but some of them are more suitable than others when you have specific needs. By describing what are the specificity of each you should be able to choose wisely the more appropriate to your needs.
Historically Jahia provided the Actions, to be able to create simple API calls based on node path and action name. Full documentation on Actions.
They are still used nowadays mostly for unique calls from client side or external calls.
- Easy and fast to do
- Useful when you need to do unique calls (like: Adding tag to a content)
- Not suitable for client-side applications
- Actions do not expose APIs using a standard such as REST or GraphQL
- Because of the nature of the Actions ( unique logical action per Action class) it will start to be complicated when you need to get multiple informations at the same time, you risk to
- have complex big Actions that deliver all the informations needed at once, making the Actions complex and not flexible
- have multiple HTTP calls from the client side to get the complete set of data.
- Allow to design RESTful Web Services
- RESTful is better than Actions to design API based on clear contracts and documented endpoints
- Useful for scripts that would need to call the endpoints for automation of certain task ( example: the Jahia module manager expose a RESTful API to manage modules)
- Still not easy to use from client-side application, for similar reasons than the Actions.
- In case you need to get multiple data you will have to chain multiple HTTP request ( It’s the case of the JCR REST API provided by Jahia, if you need more than one node data )
- REST is not a “strong” API design model, there are many different ways of doing the same thing.
- Still puts a lot of burden on the client implementation because as there is no standard REST protocol the clients must implement each REST API calls themselves
- The response body might contain a lot of unnecessary data and the only way to address this is to build into the REST API a way to specify which object fields are needed or not.
Jahia provide a GraphQL API and the possibility to extends it.
- It’s modular and extendable
- It’s design to be consumed by client-side application, because you can get all the data you need in one single call
- It’s graph oriented, so the data structure of your API is well separated, and may compose data coming from different data sources (e.g. different database tables or even different back-end APIs)
- Only the requested data is fetched, no unneeded data is sent through the network.
- Jahia provide basic JCR operations for data retrieval and manipulation
- It’s continuously evolving, Jahia dev is using it for developing the future UI of Jahia so it become more and more complete.
- Require some knowledge on GraphQL APIs ( design, syntax ), but it’s easy to get into, and a lot of online resources are available.
- As the protocol is standardized, you get request validation as well as self-documenting APIs out of the box
- Great tooling for browsing or testing APIs already exists : GraphiQL, GraphQL Playground
- Mostly oriented towards client-side apps. It will be more difficult to call GraphQL for a server-to-server interaction even if I have no doubt that GraphQL client should exist in a lot of programing language by now.
- Server-side caching technology is younger (but still feasible)
Jahia also provide the possibility to register Spring SimpleUrlHandlerMapping, by doing so you can map URLs to controllers easily.
That’s how one of our internal test API is exposed, here is a code sample from this module responsible for mapping URLs:
<bean name="jahiaTestMapping" class"org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="urlMap"> <map> <entry key="/test" value-ref="testController"/> <entry key="/test.html" value-ref="testController"/> <entry key="/test/**" value-ref="testController"/> <entry key="/createsite" value-ref="testCreateSiteController"/> </map> </property> </bean>
So you can map your own controllers to your own URL(s).
You can find a lot documentations on this Spring controllers on the web.
- You can do whatever you want to handle the requests
- You are using Spring Objects to extends the Jahia Urls
- You have to create everything from scratch by handling the requests and building the responses the old fashion way.
- Not suitable for client-side usages.
This kind of extension is really the lowest level of request/response handling you can do in Jahia. In some cases it can be useful to expose your own URLs and handle everything without any framework restrictions.
By now you should have a better idea on what type of API you can implement and in which cases it’s better to use one among the others. To summarize:
- Actions: Used for unique isolated operations, if you need one or multiple simple component(s) that perform a server side action, implement an Action. If you need more complex server side interactions it is recommended to instead consider building a RESTful or GraphQL API.
- RESTful API: This kind of API are still common in projects nowadays, the main advantage is the clear API it provides and the fact that the results is easily cacheable. REST is also a good choice when dealing with structured data that require CRUD API to be exposed. But still it’s not as flexible as GraphQL for client-side applications, rapidly changing requirements on the client-side don’t go well with the static nature of REST.
- GraphQL API: Mostly used by client-side applications ( SPA ), because it’s easy to manipulate and optimized for client-side development. client-side client provide Caching, developer tools, and other tools that will ease you client-side app development and lifecycle. Also the technology is the youngest one, and have been design to address the needs of client-side applications. This isn’t to say it can’t also be used for server-to-server calls either, that’s perfectly acceptable.
- Custom URLs/Controllers: In case you need to do everything custom, by handling the HTTP request and build the complete HTTP response, you can provide Spring URL handler mappings.
REST and GraphQL have both differents advantages. But the main question you should ask is “How my data need to be consumed ?”
At Jahia we believe in GraphQL and rely more and more on it.