Перейти к содержимому

Как написать api на java

  • автор:

С чего начать изучение API?

У меня такая ситуация, У нас есть 1 урок по ASP.Net и другой урок по разработке Android приложений, и я хочу написать веб приложение на ASP и его мобильное прил. для Android. И препод говорит что можно просто добавить API от веб приложения в мобилку и чтоб вся обработка шла туда. То есть написать бэк-енд на ASP и использовать его и в мобильном андроид приложении(хотя бэк Андроида вроде на Java). Как это сделать или как правильно задавать вопросы гуглу или как искать уроки по этой теме ??

Отслеживать
20.2k 6 6 золотых знаков 38 38 серебряных знаков 81 81 бронзовый знак
задан 20 сен 2018 в 7:16
Nurtileu Aliyas Nurtileu Aliyas
63 7 7 бронзовых знаков

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Если вы будете самостоятельно писать бэк для своего приложения то начинать нужно с изучения всего что связано с серверной частью. Если же вам уже будут давать готовое апи для вашего приложения, то нужно начинать изучать принципы отправки запросов на сервер и обработки его ответов. Я на данный момент занимаюсь разработкой клиент-серверного приложения, и мне дают документацию по апи, где прописаны все запросы необходимые для полного замещения веб-сервиса моим приложением. Для работы с апи я использую библиотеку Retrofit , хотя есть и Volley — это уже кому какая придется по душе. Лично я бы вам советовал начать читать про сами клиент-серверные приложения. Библиотеку я вам посоветую использовать Retrofit потому-что она более удобная и гибкая, и лично мне более понятна в использовании. Ниже я привожу несколько ссылок которые облегчат выполнение ваших задач:

  1. Инструмент для создания классов-моделей, которые будут использоваться в запросах.
  2. Сервис, который показывает структуру вашего ответа с сервера.
  3. Туториал для работы с ретрофитом.
  4. Статья по библиотекам которые я указывал.
  5. Еще статья по работе с retrofit

Надеюсь хоть чем-то помог, если будет что-то не понятно — не стесняйтесь и спрашивайте. Удачи, я верю что у вас все получится 🙂

Отслеживать
ответ дан 20 сен 2018 в 7:27
18k 11 11 золотых знаков 27 27 серебряных знаков 59 59 бронзовых знаков
Спасибо, попробую все что вы написали )
Commented 20 сен 2018 в 7:31
Еще добавил бы hurl.quickblox.com для отправки запросов с компа, так быстрее иногда
Commented 20 сен 2018 в 8:07
@Романыч, ссылка не работает почему-то)
Commented 20 сен 2018 в 9:13

Извиняюсь за нерабочую ссылку, так добавил бы программу PostMan для PC , удобно отправлять запросы и смотреть ответ. Мне помогает

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

Как правильно писать REST Api с Spring и Java

Я изучаю Java Spring и REST и очень запутался во всех классах и способах решениях одних и тех же проблем. Я посмотрел два онлайн-курса и выполнил туториал спинга (https://spring.io/guides/tutorials/rest/) и во всех курсах используются разные инструменты. Сначала задам вопрос, потом покажу примеры - что конкретно меня смутило. ВОПРОС: как мне выбрать "лучший" и "самый правильный" подход? Есть ли в них существенная разница (потому что из обучалок я этого не уловил - но они все очень разные) или всё просто зависит от решений команды на месте работы и на результат особо не влияет? ПРИМЕРЫ. Например, код в туториале спринга мне кажется довольно громоздким, но в нём я вижу больше всего логике - их подход с CollectionModel, EntityModel и ResponseEntity - кажется, это ещё и ближе всего к настоящему REST (к тому, как я его понял из теории). Методы там выглядели следующим образом (на примере получения всего списка работников предприятия):

 @GetMapping("/employees") CollectionModel> all() < List> employees = repository.findAll().stream() .map(assembler::toModel) .collect(Collectors.toList()); return CollectionModel.of(employees, linkTo(methodOn(EmployeeController.class).all()).withSelfRel()); > 

C другой стороны, здесь не так много классов: только контроллеры, репозитории и классы-сущности из таблиц базы данных. Код из видеокурсов мне показался проще для написания - значит, его писать и читать легче. Там все методы предлагалось делать в таком стиле (всё то же получение списка всех работников предприятия)

@GetMapping public List getAll()

И такой метод мне кажется подозрительно примитивным. и не совсем rest-ным. А вот количество классов довольно большое: здесь предлагают кроме классов с @Table, репозиториев и контроллеров использовать также сервисы, перегонять объекты классов с @Table в дополнительные объекты для работы с ними в приложении. Есть ли смысл такого нагромождения? В чём смысл тех же @Service, если сервис всего лишь является посредником в обращении к репозиторию и ничего дополнительного не делает?) Также видел предложение писать вообще не REST, а использовать Модель с атрибутами.

@GetMapping("/employees") public String getAllStaff(Model model)

Довольно много гуглил и как раз смотрел все эти курсы с целью развеять все сомнения и ответить на вопросы, но их в итоге стало лишь больше.

Java API: руководство для разработчиков и примеры использования

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

Примером использования Java API может служить разработка приложения для чтения данных из файлов. Для этого можно использовать классы из пакета java.io, такие как FileInputStream и BufferedReader.

public class ReadFileExample

public static void main(String[] args)

FileInputStream input = new FileInputStream("file.txt");

BufferedReader reader = new BufferedReader(new InputStreamReader(input));

while ((line = reader.readLine()) != null)

> catch (FileNotFoundException e)

> catch (IOException e)

В данном примере мы использовали классы FileInputStream и BufferedReader, чтобы прочитать текст из файла "file.txt" и вывести его на экран.

Также Java API содержит классы для работы с GUI, такие как JButton и JTextField, классы для работы с многопоточностью, такие как Thread и Runnable, классы для работы с сетью, такие как Socket и URLConnection, и многое другое.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *