rest api приложение java

REST API на Java без фреймворков

Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

image loader

В экосистеме Java есть много фреймворков и библиотек. Хотя и не так много, как в JavaScript, но они и не устаревают так быстро. Тем не менее, это заставило меня задуматься о том, что мы уже забыли, как писать приложения без фреймворков.

Вы можете сказать, что Spring — это стандарт и зачем изобретать велосипед? А Spark — это хороший удобный REST-фреймворк. Или Light-rest-4jis. И я скажу, что вы, конечно, правы.

Но вместе с фреймворком, помимо готовой функциональности, вы получаете много магии, сложности с изучением, дополнительные функции, которые вы, скорее всего, не будете использовать, а также баги. И чем больше стороннего кода в вашем сервисе, тем больше вероятность того, что у вас будут ошибки.

Сообщество open source очень активное, и есть большая вероятность, что ошибки в фреймворке будут быстро исправлены. Но все же, я хотел бы призвать вас подумать, действительно ли вам нужен фреймворк. Если у вас небольшой сервис или консольное приложение, возможно, вы сможете обойтись без него.

Что вы можете получить (или потерять), используя чистый Java-код? Подумайте об этом:

Когда я начал писать этот код, то часто сталкивался с ситуациями, когда отсутствовал функционал, который есть в Spring из коробки. В эти моменты, вместо того, чтобы взять Spring, надо было переосмыслить и разработать все самостоятельно.

Я понял, что для решения реальных бизнес-задач я, все же, предпочел бы использовать Spring, а не изобретать велосипед. Тем не менее, я считаю, что это упражнение было довольно интересным опытом.

Начинаем

Я буду описывать каждый шаг, но не всегда буду приводить полный исходный код. Полный код вы можете посмотреть в отдельных ветках git-репозитория.

и Jackson для JSON-сериализации

Для упрощения POJO-классов будем использовать Lombok:

и vavr для средств функционального программирования

Исходный код в ветке step-1.

Первый эндпоинт

Веб-сервер запускается на порту 8000 и предоставляет эндпоинт, который просто возвращает Hello. Это можно проверить, например, используя curl:

Исходный код в ветке step-2.

Поддержка разных HTTP-методов

Наш первый эндпоинт работает отлично, но вы можете заметить, что независимо от того, какой HTTP-метод использовать, он всегда отвечает одинаково.

Первое, что нужно сделать, это добавить код для различения методов, например:

Попробуйте еще раз такой запрос:

ответ будет примерно таким:

Исходный код в ветке step-3.

Парсинг параметров запроса

Парсинг параметров запроса — это еще одна «функция», которую нам нужно реализовать самостоятельно.

Мы могли бы распарсить параметры следующим образом:

и использовать, как показано ниже:

Полный пример в ветке step-4.

Аналогично, если мы хотим использовать параметры в path. Например:

Чтобы получить элемент по нам нужно распарсить url самостоятельно. Это становится громоздким.

Безопасность

Часто нам нужно защитить доступ к некоторым эндпоинтам. Например, это можно сделать, используя базовую аутентификацию (basic authentication).

Для каждого HttpContext мы можем установить аутентификатор, как показано ниже:

Значение “myrealm” в конструкторе BasicAuthenticator — это имя realm. Realm — это виртуальное имя, которое может быть использовано для разделения областей аутентификации.

Подробнее об этом можно прочитать в RFC 1945.

Теперь вы можете вызвать этот защищенный эндпоинт, добавив заголовок Authorization :

Для аутентификации в реальном приложении вы, вероятно, получите учетные данные из заголовка и сравните их с именем пользователя и паролем, хранящимися в базе данных.

Если вы не укажете заголовок, то API ответит статусом

Полный пример в ветке step-5.

JSON, обработка исключений и прочее

Теперь пришло время для более сложного примера.

Из моего опыта в разработке программного обеспечения наиболее распространенным API, который я разрабатывал, был обмен JSON.

Мы собираемся разработать API для регистрации новых пользователей. Для их хранения будем использовать базу данных в памяти.

У нас будет простой доменный объект User :

Я использую Lombok, чтобы избавится от бойлерплейта (конструкторы, геттеры).

В REST API я хочу передать только логин и пароль, поэтому я создал отдельный объект:

Объекты User создаются в сервисе, который будем использовать в обработчике API. Сервисный метод просто сохраняет пользователя.

В реальном приложении можно сделать больше. Например, отправлять события после успешной регистрации пользователя.

Реализация репозитория выглядит следующим образом:

Наконец, склеим все вместе в handle() :

Здесь JSON-запрос преобразуется в объект RegistrationRequest :

Также мне нужно преобразовать объект RegistrationResponse обратно в JSON-строку. Для этого используем Jackson
( com.fasterxml.jackson.databind.ObjectMapper ).

Вот как я создаю новый обработчик ( handler ) в main() :

Рабочий пример можно найти в ветке step-6. Там я также добавил глобальный обработчик исключений для отправки стандартных JSON-сообщений об ошибках. Например, если HTTP-метод не поддерживается или запрос к API сформирован неправильно.

Вы можете запустить приложение и попробовать один из следующих запросов:

Источник

Введение в Spring Boot: создание простого REST API на Java

image loader

Из-за громоздкой конфигурации зависимостей настройка Spring для корпоративных приложений превратилась в весьма утомительное и подверженное ошибкам занятие. Особенно это относится к приложениям, которые используют также несколько сторонних библиотек

Каждый раз, создавая очередное корпоративное Java-приложение на основе Spring, вам необходимо повторять одни и те же рутинные шаги по его настройке:

1. Представляем Spring Boot

Авторы Spring решили предоставить разработчикам некоторые утилиты, которые автоматизируют процедуру настройки и ускоряют процесс создания и развертывания Spring-приложений, под общим названием Spring Boot

Spring Boot — это полезный проект, целью которого является упрощение создания приложений на основе Spring. Он позволяет наиболее простым способом создать web-приложение, требуя от разработчиков минимум усилий по его настройке и написанию кода

2. Особенности Spring Boot

Spring Boot обладает большим функционалом, но его наиболее значимыми особенностями являются: управление зависимостями, автоматическая конфигурация и встроенные контейнеры сервлетов

2.1. Простота управления зависимостями

Чтобы ускорить процесс управления зависимостями, Spring Boot неявно упаковывает необходимые сторонние зависимости для каждого типа приложения на основе Spring и предоставляет их разработчику посредством так называемых starter-пакетов (spring-boot-starter-web, spring-boot-starter-data-jpa и т.д.)

Starter-пакеты представляют собой набор удобных дескрипторов зависимостей, которые можно включить в свое приложение. Это позволит получить универсальное решение для всех, связанных со Spring технологий, избавляя программиста от лишнего поиска примеров кода и загрузки из них требуемых дескрипторов зависимостей (пример таких дескрипторов и стартовых пакетов будет показан ниже)

Например, если вы хотите начать использовать Spring Data JPA для доступа к базе данных, просто включите в свой проект зависимость spring-boot-starter-data-jpa и все будет готово (вам не придется искать совместимые драйверы баз данных и библиотеки Hibernate)

Если вы хотите создать Spring web-приложение, просто добавьте зависимость spring-boot-starter-web, которая подтянет в проект все библиотеки, необходимые для разработки Spring MVC-приложений, таких как spring-webmvc, jackson-json, validation-api и Tomcat

Другими словами, Spring Boot собирает все общие зависимости и определяет их в одном месте, что позволяет разработчикам просто использовать их, вместо того, чтобы изобретать колесо каждый раз, когда они создают новое приложение

Следовательно, при использовании Spring Boot, файл pom.xml содержит намного меньше строк, чем при использовании его в Spring-приложениях

Обратитесь к документации, чтобы ознакомиться со всеми Spring Boot starter-пакетами

2.2. Автоматическая конфигурация

Второй превосходной возможностью Spring Boot является автоматическая конфигурация приложения

После выбора подходящего starter-пакета, Spring Boot попытается автоматически настроить Spring-приложение на основе добавленных вами jar-зависимостей

Например, если вы добавите Spring-boot-starter-web, Spring Boot автоматически сконфигурирует такие зарегистрированные бины, как DispatcherServlet, ResourceHandlers, MessageSource

Если вы используете spring-boot-starter-jdbc, Spring Boot автоматически регистрирует бины DataSource, EntityManagerFactory, TransactionManager и считывает информацию для подключения к базе данных из файла application.properties

Если вы не собираетесь использовать базу данных, и не предоставляете никаких подробных сведений о подключении в ручном режиме, Spring Boot автоматически настроит базу в памяти, без какой-либо дополнительной конфигурации с вашей стороны (при наличии H2 или HSQL библиотек)

Автоматическая конфигурация может быть полностью переопределена в любой момент с помощью пользовательских настроек

2.3. Встроенная поддержка сервера приложений — контейнера сервлетов

Каждое Spring Boot web-приложение включает встроенный web-сервер. Посмотрите на список контейнеров сервлетов, которые поддерживаются «из коробки»

Разработчикам теперь не надо беспокоиться о настройке контейнера сервлетов и развертывании приложения на нем. Теперь приложение может запускаться само, как исполняемый jar-файл с использованием встроенного сервера

Если вам нужно использовать отдельный HTTP-сервер, для этого достаточно исключить зависимости по умолчанию. Spring Boot предоставляет отдельные starter-пакеты для разных HTTP-серверов

Создание автономных web-приложений со встроенными серверами не только удобно для разработки, но и является допустимым решением для приложений корпоративного уровня и становится все более полезно в мире микросервисов. Возможность быстро упаковать весь сервис (например, аутентификацию пользователя) в автономном и полностью развертываемом артефакте, который также предоставляет API — делает установку и развертывание приложения значительно проще

3. Требования к установке Spring Boot

Для настройки и запуска Spring Boot приложений требуется следующее:

4. Создание Spring Boot приложения

Теперь давайте перейдем к практике и реализуем очень простой REST API для приема платежей, используя возможности Spring Boot

4.1. Создание web-проекта с использованием Maven

Создайте Maven-проект в используемой вами IDE, назвав его SpringBootRestService

Обязательно используйте версию Java 8+, поскольку Spring Boot не работает с более ранними версиями

4.2. Конфигурация pom.xml

Вторым шагом необходимо настроить Spring Boot в файле pom.xml

Все приложения Spring Boot конфигурируются от spring-boot-starter-parent, поэтому перед дальнейшим определением зависимостей, добавьте starter-parent следующим образом:

Т.к. мы создаем REST API, то необходимо в качестве зависимости использовать spring-boot-starter-web, которая неявно определяет все остальные зависимости, такие как spring-core, spring-web, spring-webmvc, servlet api, и библиотеку jackson-databind, поэтому просто добавьте в pom.xml следующее:

Теперь следующие jar-библиотеки автоматически импортируются в ваш проект:

image loader

Следующий шаг — добавляем Spring Boot плагин:

Последний шаг — сделать так, чтобы Maven генерировал исполняемый jar-файл при сборке:

Ниже приведен полный файл pom.xml:

Как видите, используя одну зависимость, мы можем создать полностью функциональное web-приложение

4.3. Создание ресурсов REST

Теперь мы собираемся создать контроллер платежей вместе с POJO-классами для запросов и ответов

Напишем класс запроса платежа:

А также класс, обрабатывающий базовый ответ, возвращаемый нашим сервисом:

А теперь создадим контроллер:

4.4. Создание основного класса приложения

Этот последний шаг заключается в создании класса конфигурации и запуска приложения. Spring Boot поддерживает новую аннотацию @SpringBootApplication, которая эквивалентна использованию @Configuration, @EnableAutoConfiguration и @ComponentScan с их атрибутами по умолчанию

Таким образом, вам просто нужно создать класс, аннотированный с помощью @SpringBootApplication, а Spring Boot включит автоматическую настройку и отсканирует ваши ресурсы в текущем пакете:

5. Развертывание приложения Spring Boot

Теперь давайте воспользуемся третьей замечательной особенностью Spring Boot — это встроенный сервер. Все, что нам нужно сделать — это создать исполняемый jar-файл с помощью Maven и запустить его, как обычное автономное приложение:

Наш REST API запущен и готов обслуживать запросы через порт 8080 (по умолчанию)

В этой статье мы рассмотрели возможности Spring Boot и создали полностью рабочий пример с использованием встроенного сервера

В переводе обновили информацию:

UPDATE:

Как заметил Lure_of_Chaos, теперь уже все можно сделать автоматически через SPRING INITIALIZR. Причем не выходя из любимой JetBrains IntelliJ IDEA.

Источник

Building REST services with Spring

REST has quickly become the de-facto standard for building web services on the web because they’re easy to build and easy to consume.

There’s a much larger discussion to be had about how REST fits in the world of microservices, but — for this tutorial — let’s just look at building RESTful services.

Why REST? REST embraces the precepts of the web, including its architecture, benefits, and everything else. This is no surprise given its author, Roy Fielding, was involved in probably a dozen specs which govern how the web operates.

What benefits? The web and its core protocol, HTTP, provide a stack of features:

Redirection and forwarding

Security (encryption and authentication)

These are all critical factors on building resilient services. But that is not all. The web is built out of lots of tiny specs, hence it’s been able to evolve easily, without getting bogged down in «standards wars».

Developers are able to draw upon 3rd party toolkits that implement these diverse specs and instantly have both client and server technology at their fingertips.

By building on top of HTTP, REST APIs provide the means to build:

Backwards compatible APIs

A spectrum of stateless to stateful services

What’s important to realize is that REST, however ubiquitous, is not a standard, per se, but an approach, a style, a set of constraints on your architecture that can help you build web-scale systems. In this tutorial we will use the Spring portfolio to build a RESTful service while leveraging the stackless features of REST.

Getting Started

As we work through this tutorial, we’ll use Spring Boot. Go to Spring Initializr and add the following dependencies to a project:

Spring Boot can work with any IDE. You can use Eclipse, IntelliJ IDEA, Netbeans, etc. The Spring Tool Suite is an open-source, Eclipse-based IDE distribution that provides a superset of the Java EE distribution of Eclipse. It includes features that make working with Spring applications even easier. It is, by no means, required. But consider it if you want that extra oomph for your keystrokes. Here’s a video demonstrating how to get started with STS and Spring Boot. This is a general introduction to familiarize you with the tools.

The Story so Far…​

Let’s start off with the simplest thing we can construct. In fact, to make it as simple as possible, we can even leave out the concepts of REST. (Later on, we’ll add REST to understand the difference.)

Big picture: We’re going to create a simple payroll service that manages the employees of a company. We’ll store employee objects in a (H2 in-memory) database, and access them (via something called JPA ). Then we’ll wrap that with something that will allow access over the internet (called the Spring MVC layer).

The following code defines an Employee in our system.

Despite being small, this Java class contains much:

@Entity is a JPA annotation to make this object ready for storage in a JPA-based data store.

a custom constructor is created when we need to create a new instance, but don’t yet have an id.

With this domain object definition, we can now turn to Spring Data JPA to handle the tedious database interactions.

Spring Data JPA repositories are interfaces with methods supporting creating, reading, updating, and deleting records against a back end data store. Some repositories also support data paging, and sorting, where appropriate. Spring Data synthesizes implementations based on conventions found in the naming of the methods in the interface.

There are multiple repository implementations besides JPA. You can use Spring Data MongoDB, Spring Data GemFire, Spring Data Cassandra, etc. For this tutorial, we’ll stick with JPA.

Spring makes accessing data easy. By simply declaring the following EmployeeRepository interface we automatically will be able to

Create new Employees

Update existing ones

Find Employees (one, all, or search by simple or complex properties)

Spring Data’s repository solution makes it possible to sidestep data store specifics and instead solve a majority of problems using domain-specific terminology.

Believe it or not, this is enough to launch an application! A Spring Boot application is, at a minimum, a public static void main entry-point and the @SpringBootApplication annotation. This tells Spring Boot to help out, wherever possible.

@SpringBootApplication is a meta-annotation that pulls in component scanning, autoconfiguration, and property support. We won’t dive into the details of Spring Boot in this tutorial, but in essence, it will fire up a servlet container and serve up our service.

Nevertheless, an application with no data isn’t very interesting, so let’s preload it. The following class will get loaded automatically by Spring:

What happens when it gets loaded?

Spring Boot will run ALL CommandLineRunner beans once the application context is loaded.

This runner will request a copy of the EmployeeRepository you just created.

Using it, it will create two entities and store them.

This isn’t the whole log, but just the key bits of preloading data. (Indeed, check out the whole console. It’s glorious.)

HTTP is the Platform

To wrap your repository with a web layer, you must turn to Spring MVC. Thanks to Spring Boot, there is little in infrastructure to code. Instead, we can focus on actions:

@RestController indicates that the data returned by each method will be written straight into the response body instead of rendering a template.

An EmployeeRepository is injected by constructor into the controller.

EmployeeNotFoundException is an exception used to indicate when an employee is looked up but not found.

When an EmployeeNotFoundException is thrown, this extra tidbit of Spring MVC configuration is used to render an HTTP 404:

@ResponseBody signals that this advice is rendered straight into the response body.

@ExceptionHandler configures the advice to only respond if an EmployeeNotFoundException is thrown.

The body of the advice generates the content. In this case, it gives the message of the exception.

To launch the application, either right-click the public static void main in PayRollApplication and select Run from your IDE, or:

Spring Initializr uses maven wrapper so type this:

Alternatively using your installed maven version type this:

When the app starts, we can immediately interrogate it.

Here you can see the pre-loaded data, in a compacted format.

If you try and query a user that doesn’t exist…​

This message nicely shows an HTTP 404 error with the custom message Could not find employee 99.

It’s not hard to show the currently coded interactions…​

If you are using Windows Command Prompt to issue cURL commands, chances are the below command won’t work properly. You must either pick a terminal that support single quoted arguments, or use double quotes and then escape the ones inside the JSON.

Then it stores newly created employee and sends it back to us:

You can update the user. Let’s change his role.

And we can see the change reflected in the output.

The way you construct your service can have significant impacts. In this situation, we said update, but replace is a better description. For example, if the name was NOT provided, it would instead get nulled out.

Finally, you can delete users like this:

This is all well and good, but do we have a RESTful service yet? (If you didn’t catch the hint, the answer is no.)

What makes something RESTful?

So far, you have a web-based service that handles the core operations involving employee data. But that’s not enough to make things «RESTful».

Pretty URLs like /employees/3 aren’t REST.

Having all the CRUD operations laid out isn’t REST.

In fact, what we have built so far is better described as RPC (Remote Procedure Call). That’s because there is no way to know how to interact with this service. If you published this today, you’d also have to write a document or host a developer’s portal somewhere with all the details.

This statement of Roy Fielding’s may further lend a clue to the difference between REST and RPC:

I am getting frustrated by the number of people calling any HTTP-based interface a REST API. Today’s example is the SocialSite REST API. That is RPC. It screams RPC. There is so much coupling on display that it should be given an X rating.

What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period. Is there some broken manual somewhere that needs to be fixed?

The side effect of NOT including hypermedia in our representations is that clients MUST hard code URIs to navigate the API. This leads to the same brittle nature that predated the rise of e-commerce on the web. It’s a signal that our JSON output needs a little help.

Introducing Spring HATEOAS, a Spring project aimed at helping you write hypermedia-driven outputs. To upgrade your service to being RESTful, add this to your build:

This tiny library will give us the constructs to define a RESTful service and then render it in an acceptable format for client consumption.

A critical ingredient to any RESTful service is adding links to relevant operations. To make your controller more RESTful, add links like this:

This is very similar to what we had before, but a few things have changed:

linkTo(methodOn(EmployeeController.class).one(id)).withSelfRel() asks that Spring HATEOAS build a link to the EmployeeController ‘s one() method, and flag it as a self link.

Roy Fielding encourages building APIs with the same techniques that made the web successful, and links are one of them.

If you restart the application and query the employee record of Bilbo, you’ll get a slightly different response than earlier:

When your curl output gets more complex it can become hard to read. Use this or other tips to prettify the json returned by curl:

HAL is a lightweight mediatype that allows encoding not just data but also hypermedia controls, alerting consumers to other parts of the API they can navigate toward. In this case, there is a «self» link (kind of like a this statement in code) along with a link back to the aggregate root.

To make the aggregate root ALSO more RESTful, you want to include top level links while ALSO including any RESTful components within.

Don’t let that first statement slip by. What does «encapsulating collections» mean? Collections of employees?

Since we’re talking REST, it should encapsulate collections of employee resources.

That’s why you fetch all the employees, but then transform them into a list of EntityModel objects. (Thanks Java 8 Streams!)

If you restart the application and fetch the aggregate root, you can see what it looks like now.

For this aggregate root, which serves up a collection of employee resources, there is a top-level «self» link. The «collection» is listed underneath the «_embedded» section; this is how HAL represents collections.

And each individual member of the collection has their information as well as related links.

What is the point of adding all these links? It makes it possible to evolve REST services over time. Existing links can be maintained while new links can be added in the future. Newer clients may take advantage of the new links, while legacy clients can sustain themselves on the old links. This is especially helpful if services get relocated and moved around. As long as the link structure is maintained, clients can STILL find and interact with things.

Simplifying Link Creation

In the code earlier, did you notice the repetition in single employee link creation? The code to provide a single link to an employee, as well as to create an «employees» link to the aggregate root, was shown twice. If that raised your concern, good! There’s a solution.

Simply put, you need to define a function that converts Employee objects to EntityModel objects. While you could easily code this method yourself, there are benefits down the road of implementing Spring HATEOAS’s RepresentationModelAssembler interface—which will do the work for you.

All the code you saw earlier in the controller can be moved into this class. And by applying Spring Framework’s @Component annotation, the assembler will be automatically created when the app starts.

To leverage this assembler, you only have to alter the EmployeeController by injecting the assembler in the constructor.

From here, you can use that assembler in the single-item employee method:

This code is almost the same, except instead of creating the EntityModel instance here, you delegate it to the assembler. Maybe that doesn’t look like much.

Applying the same thing in the aggregate root controller method is more impressive:

A key design goal of Spring HATEOAS is to make it easier to do The Right Thing™. In this scenario: adding hypermedia to your service without hard coding a thing.

At this stage, you’ve created a Spring MVC REST controller that actually produces hypermedia-powered content! Clients that don’t speak HAL can ignore the extra bits while consuming the pure data. Clients that DO speak HAL can navigate your empowered API.

But that is not the only thing needed to build a truly RESTful service with Spring.

Evolving REST APIs

With one additional library and a few lines of extra code, you have added hypermedia to your application. But that is not the only thing needed to make your service RESTful. An important facet of REST is the fact that it’s neither a technology stack nor a single standard.

REST is a collection of architectural constraints that when adopted make your application much more resilient. A key factor of resilience is that when you make upgrades to your services, your clients don’t suffer from downtime.

In the «olden» days, upgrades were notorious for breaking clients. In other words, an upgrade to the server required an update to the client. In this day and age, hours or even minutes of downtime spent doing an upgrade can cost millions in lost revenue.

Some companies require that you present management with a plan to minimize downtime. In the past, you could get away with upgrading at 2:00 a.m. on a Sunday when load was at a minimum. But in today’s Internet-based e-commerce with international customers in other time zones, such strategies are not as effective.

SOAP-based services and CORBA-based services were incredibly brittle. It was hard to roll out a server that could support both old and new clients. With REST-based practices, it’s much easier. Especially using the Spring stack.

Supporting changes to the API

Uh oh. Didn’t think of that.

Downtime = lost money. Is management ready for that?

There is an old strategy that precedes REST by years.

Never delete a column in a database.

You can always add columns (fields) to a database table. But don’t take one away. The principle in RESTful services is the same.

Add new fields to your JSON representations, but don’t take any away. Like this:

And not only should you show this information in both the «old way» and the «new way», you should also process incoming data both ways.

How? Simple. Like this:

A «virtual» getter for the old name property, getName() is defined. It uses the firstName and lastName fields to produce a value.

Of course not EVERY change to your API is as simple as splitting a string or merging two strings. But it’s surely not impossible to come up with a set of transforms for most scenarios, right?

Don’t forget to go and change how you preload your database (in LoadDatabase ) to use this new constructor.

Proper Responses

Another step in the right direction involves ensuring that each of your REST methods returns a proper response. Update the POST method like this:

Spring MVC’s ResponseEntity is used to create an HTTP 201 Created status message. This type of response typically includes a Location response header, and we use the URI derived from the model’s self-related link.

Additionally, return the model-based version of the saved object.

With these tweaks in place, you can use the same endpoint to create a new employee resource, and use the legacy name field:

The output is shown below:

The PUT controller method needs similar tweaks:

The Employee object built from the save() operation is then wrapped using the EmployeeModelAssembler into an EntityModel object. Using the getRequiredLink() method, you can retrieve the Link created by the EmployeeModelAssembler with a SELF rel. This method returns a Link which must be turned into a URI with the toUri method.

Since we want a more detailed HTTP response code than 200 OK, we will use Spring MVC’s ResponseEntity wrapper. It has a handy static method created() where we can plug in the resource’s URI. It’s debatable if HTTP 201 Created carries the right semantics since we aren’t necessarily «creating» a new resource. But it comes pre-loaded with a Location response header, so run with it.

That employee resource has now been updated and the location URI sent back. Finally, update the DELETE operation suitably:

This returns an HTTP 204 No Content response.

Making changes to the fields in the Employee class will require coordination with your database team, so that they can properly migrate existing content into the new columns.

You are now ready for an upgrade that will NOT disturb existing clients while newer clients can take advantage of the enhancements!

By the way, are you worried about sending too much information over the wire? In some systems where every byte counts, evolution of APIs may need to take a backseat. But don’t pursue such premature optimization until you measure.

Building links into your REST API

So far, you’ve built an evolvable API with bare bones links. To grow your API and better serve your clients, you need to embrace the concept of Hypermedia as the Engine of Application State.

What does that mean? In this section, you’ll explore it in detail.

Business logic inevitably builds up rules that involve processes. The risk of such systems is we often carry such server-side logic into clients and build up strong coupling. REST is about breaking down such connections and minimizing such coupling.

To show how to cope with state changes without triggering breaking changes in clients, imagine adding a system that fulfills orders.

As a first step, define an Order record:

The class requires a JPA @Table annotation changing the table’s name to CUSTOMER_ORDER because ORDER is not a valid name for table.

It includes a description field as well as a status field.

Orders must go through a certain series of state transitions from the time a customer submits an order and it is either fulfilled or cancelled. This can be captured as a Java enum :

This enum captures the various states an Order can occupy. For this tutorial, let’s keep it simple.

To support interacting with orders in the database, you must define a corresponding Spring Data repository:

With this in place, you can now define a basic OrderController :

It contains the same REST controller setup as the controllers you’ve built so far.

The first two Spring MVC routes handle the aggregate root as well as a single item Order resource request.

The third Spring MVC route handles creating new orders, by starting them in the IN_PROGRESS state.

All the controller methods return one of Spring HATEOAS’s RepresentationModel subclasses to properly render hypermedia (or a wrapper around such a type).

But that would be wrong.

What happens when you introduce a new state in this flow? The placement of various buttons on the UI would probably be erroneous.

What if you changed the name of each state, perhaps while coding international support and showing locale-specific text for each state? That would most likely break all the clients.

Enter HATEOAS or Hypermedia as the Engine of Application State. Instead of clients parsing the payload, give them links to signal valid actions. Decouple state-based actions from the payload of data. In other words, when CANCEL and COMPLETE are valid actions, dynamically add them to the list of links. Clients only need show users the corresponding buttons when the links exist.

This decouples clients from having to know WHEN such actions are valid, reducing the risk of the server and its clients getting out of sync on the logic of state transitions.

Having already embraced the concept of Spring HATEOAS RepresentationModelAssembler components, putting such logic in the OrderModelAssembler would be the perfect place to capture this business rule:

If clients can adopt HAL and the ability to read links instead of simply reading the data of plain old JSON, they can trade in the need for domain knowledge about the order system. This naturally reduces coupling between client and server. And it opens the door to tuning the flow of order fulfillment without breaking clients in the process.

To round out order fulfillment, add the following to the OrderController for the cancel operation:

And add this to the OrderController as well for order completion:

This implements similar logic to prevent an Order status from being completed unless in the proper state.

Let’s update LoadDatabase to pre-load some Order ​s along with the Employee ​s it was loading before.

Now you can test things out!

To use the newly minted order service, just perform a few operations:

This HAL document immediately shows different links for each order, based upon its present state.

The first order, being COMPLETED only has the navigational links. The state transition links are not shown.

The second order, being IN_PROGRESS additionally has the cancel link as well as the complete link.

Try cancelling an order:

This response shows an HTTP 200 status code indicating it was successful. The response HAL document shows that order in its new state ( CANCELLED ). And the state-altering links gone.

If you try the same operation again…​

…​you see an HTTP 405 Method Not Allowed response. DELETE has become an invalid operation. The Problem response object clearly indicates that you aren’t allowed to «cancel» an order already in the «CANCELLED» status.

Additionally, trying to complete the same order also fails:

With all this in place, your order fulfillment service is capable of conditionally showing what operations are available. It also guards against invalid operations.

By leveraging the protocol of hypermedia and links, clients can be built sturdier and less likely to break simply because of a change in the data. And Spring HATEOAS eases building the hypermedia you need to serve to your clients.

Summary

Throughout this tutorial, you have engaged in various tactics to build REST APIs. As it turns out, REST isn’t just about pretty URIs and returning JSON instead of XML.

Instead, the following tactics help make your services less likely to break existing clients you may or may not control:

Don’t remove old fields. Instead, support them.

Use rel-based links so clients don’t have to hard code URIs.

Retain old links as long as possible. Even if you have to change the URI, keep the rels so older clients have a path onto the newer features.

Use links, not payload data, to instruct clients when various state-driving operations are available.

It may appear to be a bit of effort to build up RepresentationModelAssembler implementations for each resource type and to use these components in all of your controllers. But this extra bit of server-side setup (made easy thanks to Spring HATEOAS) can ensure the clients you control (and more importantly, those you don’t) can upgrade with ease as you evolve your API.

This concludes our tutorial on how to build RESTful services using Spring. Each section of this tutorial is managed as a separate subproject in a single github repo:

nonrest — Simple Spring MVC app with no hypermedia

rest — Spring MVC + Spring HATEOAS app with HAL representations of each resource

evolution — REST app where a field is evolved but old data is retained for backward compatibility

links — REST app where conditional links are used to signal valid state changes to clients

To do some more exploring check out the following video by Spring teammate Oliver Gierke:

Want to write a new guide or contribute to an existing one? Check out our contribution guidelines.

All guides are released with an ASLv2 license for the code, and an Attribution, NoDerivatives creative commons license for the writing.

tut rest

Get the Code

Table of contents

footer circles dc4b03d4edc1f3b7b42a45bdcce411c8

Get ahead

VMware offers training and certification to turbo-charge your progress.

Get support

Spring Runtime offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Upcoming events

Check out all the upcoming events in the Spring community.

Источник

Понравилась статья? Поделить с друзьями:
Добавить комментарий
  • Как сделать успешный бизнес на ритуальных услугах
  • Выездной кейтеринг в России
  • Риски бизнеса: без чего не обойтись на пути к успеху
  • rest 3 формы глагола в английском
  • responsa это в римском праве