Как реализовать на java (RestFull) подключение к стороннему сервису (API)?
Дорогие форумчане, поделитесь опытом — как реализовать подключение стороннего сервиса (API-ссылки есть) на основе Java Spring Boot? Мое серверное приложение в итоге должно выступать в роли посредника (агрегатора).Проблема в следующем — я знаю, как возвращать html страницу, JPA, но не представляю (Google не помог), как предоставить клиенту через Get-запрос сервис стороннего сайта, например курс валют, карту, погоду и т.д.
Отслеживать
задан 12 окт 2021 в 7:54
1 2 2 бронзовых знака
Пожалуйста, исправьте вопрос, чтобы он отражал конкретную проблему с достаточным количеством деталей для возможности дать адекватный ответ.
12 окт 2021 в 7:55
Вам нужно использовать HttpClient. Они есть разные. Есть и «штатный» спринговый. Почитайте attacomsian.com/blog/http-requests-resttemplate-spring-boot
Как подключить api java
Чтобы подключить API в проекте с использованием Gradle , нужно выполнить следующие шаги:
- Добавить зависимость в файл build.gradle в блок dependencies . Например, если вы хотите подключить библиотеку для работы с Twitter API , вам нужно добавить следующую зависимость:
dependencies compile group: 'org.twitter4j', name: 'twitter4j-core', version: '4.0.7' >
- После добавления зависимости, запустите команду gradle build , чтобы загрузить зависимости и создать проект.
- После успешного выполнения команды, вы можете использовать API в своем проекте, импортировав соответствующие классы и методы.
REST API на Java без фреймворков
В экосистеме Java есть много фреймворков и библиотек. Хотя и не так много, как в JavaScript, но они и не устаревают так быстро. Тем не менее, это заставило меня задуматься о том, что мы уже забыли, как писать приложения без фреймворков.
Вы можете сказать, что Spring — это стандарт и зачем изобретать велосипед? А Spark — это хороший удобный REST-фреймворк. Или Light-rest-4jis. И я скажу, что вы, конечно, правы.
Но вместе с фреймворком, помимо готовой функциональности, вы получаете много магии, сложности с изучением, дополнительные функции, которые вы, скорее всего, не будете использовать, а также баги. И чем больше стороннего кода в вашем сервисе, тем больше вероятность того, что у вас будут ошибки.
Сообщество open source очень активное, и есть большая вероятность, что ошибки в фреймворке будут быстро исправлены. Но все же, я хотел бы призвать вас подумать, действительно ли вам нужен фреймворк. Если у вас небольшой сервис или консольное приложение, возможно, вы сможете обойтись без него.
Что вы можете получить (или потерять), используя чистый Java-код? Подумайте об этом:
- ваш код может быть намного чище и понятнее (а может и в полном беспорядке, если вы плохой программист)
- у вас будет больше контроля над вашим кодом, вы не будете ограничены рамками фреймворка (хотя вам придется писать больше своего кода для функциональности, которую фреймворк предоставляет из коробки)
- ваше приложение будет развертываться и запускаться гораздо быстрее, потому что фреймворку не нужно инициализировать десятки классов (или не будет запускаться вообще, если вы перепутаете что-то, например, в многопоточности)
- если вы развертываете приложение в Docker, то ваши образы будут намного меньше, потому что ваши jar также будут меньше
Когда я начал писать этот код, то часто сталкивался с ситуациями, когда отсутствовал функционал, который есть в Spring из коробки. В эти моменты, вместо того, чтобы взять Spring, надо было переосмыслить и разработать все самостоятельно.
Я понял, что для решения реальных бизнес-задач я, все же, предпочел бы использовать Spring, а не изобретать велосипед. Тем не менее, я считаю, что это упражнение было довольно интересным опытом.
Начинаем
Я буду описывать каждый шаг, но не всегда буду приводить полный исходный код. Полный код вы можете посмотреть в отдельных ветках git-репозитория.
Сначала создайте новый Maven-проект со следующим pom.xml .
4.0.0 com.consulner.httpserver pure-java-rest-api 1.0-SNAPSHOT 11 $ $
Добавьте в зависимости java.xml.bind , потому что он был удален в JDK 11 (JEP-320).
org.glassfish.jaxb jaxb-runtime 2.4.0-b180608.0325
и Jackson для JSON-сериализации
com.fasterxml.jackson.core jackson-databind 2.9.7
Для упрощения POJO-классов будем использовать Lombok:
org.projectlombok lombok 1.18.0 provided
и vavr для средств функционального программирования
io.vavr vavr 0.9.2
Также создадим основной пустой класс Application .
Исходный код в ветке step-1.
Первый эндпоинт
В основе нашего веб-приложения будет класс com.sun.net.httpserver.HttpServer . И простейший эндпоинт (endpoint) /api/hello может выглядеть следующим образом:
package com.consulner.api; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import com.sun.net.httpserver.HttpServer; class Application < public static void main(String[] args) throws IOException < int serverPort = 8000; HttpServer server = HttpServer.create(new InetSocketAddress(serverPort), 0); server.createContext("/api/hello", (exchange ->< String respText = "Hello!"; exchange.sendResponseHeaders(200, respText.getBytes().length); OutputStream output = exchange.getResponseBody(); output.write(respText.getBytes()); output.flush(); exchange.close(); >)); server.setExecutor(null); // creates a default executor server.start(); > >
Веб-сервер запускается на порту 8000 и предоставляет эндпоинт, который просто возвращает Hello. Это можно проверить, например, используя curl:
Исходный код в ветке step-2.
Поддержка разных HTTP-методов
Наш первый эндпоинт работает отлично, но вы можете заметить, что независимо от того, какой HTTP-метод использовать, он всегда отвечает одинаково.
curl -X POST localhost:8000/api/hello curl -X PUT localhost:8000/api/hello
Первое, что нужно сделать, это добавить код для различения методов, например:
server.createContext("/api/hello", (exchange -> < if ("GET".equals(exchange.getRequestMethod())) < String respText = "Hello!"; exchange.sendResponseHeaders(200, respText.getBytes().length); OutputStream output = exchange.getResponseBody(); output.write(respText.getBytes()); output.flush(); >else < exchange.sendResponseHeaders(405, -1);// 405 Method Not Allowed >exchange.close(); >));
Попробуйте еще раз такой запрос:
curl -v -X POST localhost:8000/api/hello
ответ будет примерно таким:
> POST /api/hello HTTP/1.1 > Host: localhost:8000 > User-Agent: curl/7.61.0 > Accept: */* > < HTTP/1.1 405 Method Not Allowed
Есть также несколько моментов, которые нужно помнить. Например, не забыть сделать flush() для OutputStream и close() для exchange . При использовании Spring мне об этом даже не приходилось думать.
Исходный код в ветке step-3.
Парсинг параметров запроса
Парсинг параметров запроса — это еще одна «функция», которую нам нужно реализовать самостоятельно.
Допустим, мы хотим, чтобы наш hello api получал имя в параметре name , например:
curl localhost:8000/api/hello?name=Marcin Hello Marcin!
Мы могли бы распарсить параметры следующим образом:
public static Map> splitQuery(String query) < if (query == null || "".equals(query)) < return Collections.emptyMap(); >return Pattern.compile("&").splitAsStream(query) .map(s -> Arrays.copyOf(s.split(" java">Map> params = splitQuery(exchange.getRequestURI().getRawQuery()); String noNameText = "Anonymous"; String name = params.getOrDefault("name", List.of(noNameText)).stream().findFirst().orElse(noNameText); String respText = String.format("Hello %s!", name);
Полный пример в ветке step-4.
Аналогично, если мы хотим использовать параметры в path. Например:
curl localhost:8000/api/items/1
Чтобы получить элемент по нам нужно распарсить url самостоятельно. Это становится громоздким.
Безопасность
Часто нам нужно защитить доступ к некоторым эндпоинтам. Например, это можно сделать, используя базовую аутентификацию (basic authentication).
Для каждого HttpContext мы можем установить аутентификатор, как показано ниже:
HttpContext context = server.createContext("/api/hello", (exchange -> < // здесь ничего не изменяем >)); context.setAuthenticator(new BasicAuthenticator("myrealm") < @Override public boolean checkCredentials(String user, String pwd) < return user.equals("admin") && pwd.equals("admin"); >>);
Значение “myrealm” в конструкторе BasicAuthenticator — это имя realm. Realm — это виртуальное имя, которое может быть использовано для разделения областей аутентификации.
Подробнее об этом можно прочитать в RFC 1945.
Теперь вы можете вызвать этот защищенный эндпоинт, добавив заголовок Authorization :
curl -v localhost:8000/api/hello?name=Marcin -H 'Authorization: Basic YWRtaW46YWRtaW4='
Текст после «Basic» — это кодированный в Base64 текст admin:admin , который представляет собой учетные данные, жестко закодированные в нашем примере.
Для аутентификации в реальном приложении вы, вероятно, получите учетные данные из заголовка и сравните их с именем пользователя и паролем, хранящимися в базе данных.
Если вы не укажете заголовок, то API ответит статусом
HTTP/1.1 401 Unauthorized
Полный пример в ветке step-5.
JSON, обработка исключений и прочее
Теперь пришло время для более сложного примера.
Из моего опыта в разработке программного обеспечения наиболее распространенным API, который я разрабатывал, был обмен JSON.
Мы собираемся разработать API для регистрации новых пользователей. Для их хранения будем использовать базу данных в памяти.
У нас будет простой доменный объект User :
@Value @Builder public class User
Я использую Lombok, чтобы избавится от бойлерплейта (конструкторы, геттеры).
В REST API я хочу передать только логин и пароль, поэтому я создал отдельный объект:
@Value @Builder public class NewUser
Объекты User создаются в сервисе, который будем использовать в обработчике API. Сервисный метод просто сохраняет пользователя.
public String create(NewUser user)
В реальном приложении можно сделать больше. Например, отправлять события после успешной регистрации пользователя.
Реализация репозитория выглядит следующим образом:
import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import com.consulner.domain.user.NewUser; import com.consulner.domain.user.User; import com.consulner.domain.user.UserRepository; public class InMemoryUserRepository implements UserRepository < private static final Map USERS_STORE = new ConcurrentHashMap(); @Override public String create(NewUser newUser) < String User user = User.builder() .id(id) .login(newUser.getLogin()) .password(newUser.getPassword()) .build(); USERS_STORE.put(newUser.getLogin(), user); return id; >>
Наконец, склеим все вместе в handle() :
protected void handle(HttpExchange exchange) throws IOException < if (!exchange.getRequestMethod().equals("POST")) < throw new UnsupportedOperationException(); >RegistrationRequest registerRequest = readRequest(exchange.getRequestBody(), RegistrationRequest.class); NewUser user = NewUser.builder() .login(registerRequest.getLogin()) .password(PasswordEncoder.encode(registerRequest.getPassword())) .build(); String userId = userService.create(user); exchange.getResponseHeaders().set(Constants.CONTENT_TYPE, Constants.APPLICATION_JSON); exchange.sendResponseHeaders(StatusCode.CREATED.getCode(), 0); byte[] response = writeResponse(new RegistrationResponse(userId)); OutputStream responseBody = exchange.getResponseBody(); responseBody.write(response); responseBody.close(); >
Здесь JSON-запрос преобразуется в объект RegistrationRequest :
@Value class RegistrationRequest
который позже я сопоставляю с объектом NewUser , чтобы сохранить его в базе данных и отправить ответ в виде JSON.
Также мне нужно преобразовать объект RegistrationResponse обратно в JSON-строку. Для этого используем Jackson
( com.fasterxml.jackson.databind.ObjectMapper ).
Вот как я создаю новый обработчик ( handler ) в main() :
public static void main(String[] args) throws IOException < int serverPort = 8000; HttpServer server = HttpServer.create(new InetSocketAddress(serverPort), 0); RegistrationHandler registrationHandler = new RegistrationHandler(getUserService(), getObjectMapper(), getErrorHandler()); server.createContext("/api/users/register", registrationHandler::handle); // here follows the rest.. >
Рабочий пример можно найти в ветке step-6. Там я также добавил глобальный обработчик исключений для отправки стандартных JSON-сообщений об ошибках. Например, если HTTP-метод не поддерживается или запрос к API сформирован неправильно.
Вы можете запустить приложение и попробовать один из следующих запросов:
- пример правильного запроса
curl -X POST localhost:8000/api/users/register -d ''
curl -v -X POST localhost:8000/api/users/register -d ''
Кроме того, я случайно столкнулся с проектом java-express, который является Java-аналогом фреймворка Express для Node.js. В нем также используется jdk.httpserver , поэтому все концепции, описанные в этой статье, вы можете изучить на реальном фреймворке, который, к тому же, достаточно мал для изучения его кода.
- Блог компании OTUS
- Программирование
- Java
Как использовать Java API for OAuth
Узнайте, как использовать Java API для работы с протоколом OAuth, и интегрируйте ваше приложение с веб-сервисами простыми шагами!
Алексей Кодов
Автор статьи
10 июля 2023 в 17:48
OAuth – это открытый стандарт авторизации, который позволяет клиентским приложениям получать доступ к ресурсам пользователя на других веб-сервисах. В этой статье мы рассмотрим, как использовать Java API для работы с протоколом OAuth.
Шаг 1: Подключение библиотеки
Для начала нам потребуется подключить библиотеку scribejava-core . Добавьте следующую зависимость в файл pom.xml вашего проекта:
<dependency> <groupId>com.github.scribejava</groupId> <artifactId>scribejava-core</artifactId> <version>8.4.0</version> </dependency>
Шаг 2: Создание OAuth-сервиса
Теперь создадим экземпляр сервиса OAuth, который будет обрабатывать запросы к API. Вам потребуется указать следующие данные:
- ключ клиента (client key)
- секрет клиента (client secret)
- обратный URL-адрес (callback URL)
import com.github.scribejava.core.builder.ServiceBuilder; import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.oauth.OAuth20Service; import com.github.scribejava.apis.GoogleApi20; public class OAuthExample < private static final String CLIENT_KEY = "your-client-key"; private static final String CLIENT_SECRET = "your-client-secret"; private static final String CALLBACK_URL = "your-callback-url"; public static void main(String[] args) < OAuth20Service authService = new ServiceBuilder(CLIENT_KEY) .apiSecret(CLIENT_SECRET) .callback(CALLBACK_URL) .build(GoogleApi20.instance()); >>
Java-разработчик: новая работа через 11 месяцев
Получится, даже если у вас нет опыта в IT

Шаг 3: Получение авторизационного URL
После создания сервиса OAuth, мы можем получить авторизационный URL, который будет использоваться для запроса разрешения пользователя на доступ к его данным:
public class OAuthExample < // . код из предыдущего шага . public static void main(String[] args) < // . создание сервиса OAuth . String authUrl = authService.getAuthorizationUrl(); System.out.println("Пожалуйста, откройте следующий URL в вашем браузере и предоставьте доступ:"); System.out.println(authUrl); >>
Шаг 4: Получение токена доступа
После того, как пользователь предоставит доступ, он будет перенаправлен на обратный URL-адрес с кодом авторизации. Этот код необходим для получения токена доступа:
public class OAuthExample < // . код из предыдущих шагов . public static void main(String[] args) < // . создание сервиса OAuth и получение авторизационного URL . System.out.println("Введите код авторизации:"); String authCode = new Scanner(System.in).nextLine(); OAuth2AccessToken accessToken = authService.getAccessToken(authCode); System.out.println("Токен доступа: " + accessToken.getAccessToken()); >>
Шаг 5: Использование токена доступа для обращения к API
Теперь у нас есть токен доступа, который мы можем использовать для выполнения запросов к API:
import com.github.scribejava.core.model.OAuthRequest; import com.github.scribejava.core.model.Verb; import com.github.scribejava.core.model.Response; public class OAuthExample < // . код из предыдущих шагов . public static void main(String[] args) < // . создание сервиса OAuth, получение авторизационного URL и токена доступа . OAuthRequest request = new OAuthRequest(Verb.GET, "https://www.googleapis.com/oauth2/v1/userinfo"); authService.signRequest(accessToken, request); Response response = authService.execute(request); System.out.println("Ответ API: " + response.getBody()); >>
Теперь вы знаете, как использовать Java API для работы с протоколом OAuth. Попробуйте применить эти знания для интеграции вашего приложения с другими веб-сервисами. Удачи вам в разработке!
