New stateless endpoints are one of the main features introduced in Vaadin 15. You can use them in client-side TypeScript views to connect to backend logic on the Java server. At first glance, this looks really similar to existing solutions, such as REST. There are indeed many similarities, but there are also key differences to keep in mind.
Vaadin endpoints are an opinionated form of REST
REST is a generic pattern that defines how a client reads or modifies a server-side resource by sending a message and receiving a response. It uses simple and universal mechanisms, such as HTTP and JSON. This makes it easy to get started and facilitates interoperability between different programming languages and frameworks.
At the same time, this also means that two different REST APIs can use quite different conventions, even though they follow the same generic patterns. This, in turn, means that there's lots of configuration options to choose from in the libraries that help you create REST clients or servers.
Vaadin’s new endpoint functionality differs in that the focus is on only one thing: communication between a Vaadin view implemented in TypeScript and a Vaadin backend service implemented in Java. If you look at what's actually sent over the network, you will see something that looks very much like REST. This is a small bonus that lets you reuse existing tools, for example for load testing, but you shouldn’t, in general, use it at this abstraction level.
If you look at a simple Vaadin endpoint and compare it to a generic REST endpoint implementation, you will notice a distinctive lack of configuration. It's optimized for one specific use case, so it isn't necessary to bury the actual application logic between annotations to define details such as URL mappings, parameter names, content types or HTTP verbs.
@Endpoint
public class HelloEndpoint {
public String sayHello(String name) {
return "Hello " + name;
}
}
This simplicity extends to the client side as well: here, you get a generated TypeScript interface that is automatically hooked up to make calls to the endpoint. The generated code takes into account modern browser features, such as the async and await keywords, and makes usage almost as simple as calling a local function.
import * as helloEndpoint from './generated/HelloEndpoint'
async makeCall() {
const greeting = await helloEndpoint.sayHello('Vaadin');
console.log(greeting);
}
Behind the scenes, Vaadin endpoints rely on Swagger to automatically generate the TypeScript code. Swagger is a tool commonly used to work with REST APIs. While you could use Swagger with your own generic REST endpoints to generate similar code, the point is that it is all done for you: you have the whole chain from parsing Java source files all the way to putting a generated TypeScript class in the right location integrated into the Vaadin toolchain.
You can combine Vaadin endpoints and REST
There is no such thing as a free lunch. You pay for this convenience by giving up some flexibility. What you have is basically a backend API that is specific for this particular client implementation. For example, you can't choose the HTTP verb, such as GET or POST, depending on the semantics of each endpoint method. We're also not promising that the REST API of an endpoint will stay the same in future Vaadin versions. Furthermore, the code generator only supports REST patterns that are used by the Vaadin endpoints.
This doesn't mean that all hope is lost if you need to support other clients or existing REST APIs. When you use a generic REST API in your application, it often becomes apparent that the API doesn't fully align with the specifics of your application. You may need to combine data from two different endpoints or do some other aggregation or conversion. The simplest approach in these situations is typically to combine, aggregate and convert the data in the client-side implementation. This means that clients need to do multiple requests and download redundant data. You can avoid this problem with a dedicated Vaadin endpoint that fetches data from the original REST endpoints, so that additional fetching and processing is done on the server.
The inherent simplicity of the Vaadin endpoints mean that this additional layer requires very little additional code. Defining endpoints specifically for each client implementation gives you lots of flexibility on how you process the data. The generic endpoints are usually maintained by a separate team that has their own priorities, whereas the Vaadin endpoints belong to one specific application and are therefore maintained by the application team.
Vaadin 15 is only the beginning
Vaadin endpoints are really about using REST as a technical foundation and then adding an opinionated convenience layer on top. They are optimized for the very useful use case when endpoints are used for the specific needs of a single client implementation.
The base functionality introduced in Vaadin 15 is only a starting point for a whole new set of functionality related to client-server communication. The team is currently working on a way to automate form binding with client-side validation, based on Bean Validation annotations on the corresponding Java types. Further ahead in the roadmap, there are plans to integrate server push into the same format, as well as a way to automatically cache data sent over the endpoints so that the application can also work offline.