- Блог Виктора Деревянко
- пятница, 24 января 2014 г.
- REST под Android. Часть 2: разрабатываем API
- Принципы разработки REST API
- Apigee
- Другие ресурсы
- Тестовый пример: набор книг
- Первая попытка описания API: список URL в текстовом файле
- Инструменты для описания API
- Вторая попытка описания API: Apiary.io
- Выводы
- Android для начинающих: использование REST API
- 1. Включение доступа к Интернету
- 2. Создание фоновых потоков
- 3. Создание HTTP-соединения
- 4. Добавление заголовков запросов
- 5. Чтение ответов
- 6. Разбор JSON ответов
- 7. Использование разных HTTP методов
- 8. Кэширование ответов
- Заключение
- REST API на Java без фреймворков
- Начинаем
- Первый эндпоинт
- Поддержка разных HTTP-методов
- Парсинг параметров запроса
- Безопасность
- JSON, обработка исключений и прочее
Блог Виктора Деревянко
О жизни, о программировании. Все публикуемые исходные коды можно взять здесь
пятница, 24 января 2014 г.
REST под Android. Часть 2: разрабатываем API
Прежде чем переходить к разработке тестового проекта на RoboSpice, необходимо определиться с API для тестового проекта. Разумеется, можно взять одно из готовых API — благо их сейчас сотни. Однако гораздо интереснее написать свое, тем более, что это нетривиальный процесс. Рассмотрим, как пишутся REST API, какие инструменты для этого существуют, и попробуем реализовать простейшее тестовое API.
Принципы разработки REST API
Apigee
Там же на отдельной странице собраны примеры готовых REST API (github, twitter и т.д.). Специальная консоль позволяет поработать с выбранным API прямо из браузера.
Другие ресурсы
- Книга RESTful Web APIs (2013) by Leonard Richardson, Mike Amundsen, Sam Ruby.
- REST+JSON API Design — Best Practices for Developers: slides, video
- Best Practices for Designing a Pragmatic RESTful API by Vinay Sahni
- REST and JSON API guidelines and best practices by Niels Krijger — удобная шпаргалка, краткая компиляция из других источников.
- HTTP: The Definitive Guide by David Gourley, Brian Totty, Marjorie Sayer, Anshu Aggarwal, Sailu Reddy. В книге детально рассмотрен HTTP протокол, на котором в большинстве случаев реализуются REST API. Так же HTTP посвящена отдельная глава «HTTP for APIs» в книге «RESTful Web APIs».
Тестовый пример: набор книг
Первая попытка описания API: список URL в текстовом файле
Договоримся, что для формат представления ресурсов можно задавать следующим образом:
Теперь зафиксируем способ обработки ошибок. Будем считать, что в случае успеха сервер возвращает код 200 — OK , в случае ошибки один из следующих кодов: 400 — Bad Request, 500 — Internal Server Error . Для наших целей вполне достаточно, хотя можно задействовать и другие коды.
В случае ошибки сервер обязан вернуть сообщение с расшифровкой ошибки в формате:
Осталось описать формат представления ресурса и списков ресурсов.
- [1] получить полный список книг
- [2] получить информацию о книге
- [3] добавить книгу в набор
- [4] удалить книгу из набора
- [5] редактировать информацию о книге
- [6] провести поиск книг по автору, по названию — аналогично [1]
Инструменты для описания API
Вторая попытка описания API: Apiary.io
В целом, работа с API Blueprint Language не вызвала каких-то особых проблем. Смутил только один момент, с которым так и не удалось разобраться. Я создал ресурс Book: и действия к нему Параметр fields может использоваться только с GET, а в PATCN и DELETE его быть не может. Набор параметров я задаю отдельно для каждого действия. Тем не менее, в документации для Edit и Delete параметр fields присутствует в URL, что несколько сбивает с толку. Причем ниже, в списке возможных параметров, он отсутствует.
Выводы
- Прежде чем разрабатывать собственное REST API, имеет смысл ознакомиться как минимум с Web API Design. Crafting Interfaces that Developers Love (pdf), чтобы не наделать грубых ошибок.
- Сервис apiary.io — весьма функционален. Разрабатывать REST API на нем гораздо удобнее, чем в просто фиксировать список URL в текстовом файле. Возможность проверки реализации на соответствие спецификации и Mock-сервер стоят того, чтобы потратить время на изучение API Blueprint Language.
Цель достигнута — BooksSet REST API для тестового проекта создано. Переходим к разработке проекта. Об этом — в следующий раз.
Mindmap, созданный в процессе работы над этой статьей, можно скачать здесь, в формате Freemind 1.0 (портативная версия: freemind-bin-1.0.0.zip).
Update Mock-сервер Apiary не поддерживает компрессию gzip. Может когда-нибудь сделают, особенно если за эту функцию проголосует достаточное количество пользователей.
Источник
Android для начинающих: использование REST API
Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)
Большинство из нас стали весьма жадны до новой информации, что в Интернете является такой важной частью нашей жизни. Поэтому создание приложений Android со статичным контентом может быть плохой идеей. Вместо этого вам следует рассмотреть возможность создания приложений, которые могут отображать свежий контент каждый раз, когда пользователь их открывает.
Это может звучать сложно, но с большим количеством сайтов, которые раскрывают свои ресурсы через REST API, на самом деле это довольно просто. (Смотрите руководство для начинающих по HTTP и REST для примера.)
В этом уроке я расскажу вам, как использовать классы и методы, доступные в Android SDK, для подключения к удаленным веб-серверам и взаимодействия с ними с использованием их REST API.
1. Включение доступа к Интернету
Использование REST API, очевидно, связано с использованием Интернета. Тем не менее, приложения Android могут получить доступ к Интернету только в том случае, если у них есть разрешение android.permission.INTERNET . Поэтому перед началом написания любого сетевого кода вы должны убедиться, что в файле манифеста вашего проекта присутствуют следующие uses-permission теги:
Поскольку android.permission.INTERNET не считается опасным разрешением, вам не нужно запрашивать его во время выполнения на устройствах с уровнем API 23 или выше.
2. Создание фоновых потоков
Платформа Android не позволяет выполнять сетевые операции в основном потоке приложения. Поэтому весь ваш сетевой код должен принадлежать фоновому потоку. Самый простой способ создать такой поток — использовать метод execute() класса AsyncTask . В качестве единственного аргумента execute() ожидает объект Runnable .
Если вы хотите узнать больше о выполнении операций в фоновом потоке, я предлагаю вам прочитать этот учебник о фоновых операциях из серии Android для начинающих.
3. Создание HTTP-соединения
Используя метод openConnection() класса URL , вы можете быстро настроить соединение с любой конечной точкой REST. Возвращаемое значение openConnection() должно быть передано в экземпляр HttpURLConnection или HttpsURLConnection , в зависимости от доступа к конечной точке через HTTP или HTTPS. Оба HttpURLConnection и HttpsURLConnection позволяют выполнять такие операции, как добавление заголовков запросов и чтение ответов.
В следующем фрагменте кода показано, как настроить соединение с корневой конечной точкой API GitHub:
Обратите внимание, что HttpsURLConnection является подклассом класса HttpURLConnection .
4. Добавление заголовков запросов
Большинство веб-сайтов, предлагающих REST API, хотят иметь возможность однозначно идентифицировать ваше приложение. Самый простой способ помочь им сделать это — включить уникальный заголовок User-Agent во все ваши запросы.
Чтобы добавить заголовок User-Agent в ваш запрос, вы должны использовать метод setRequestProperty() объекта HttpURLConnection . Например, вот как вы устанавливаете заголовок User-Agent в my-rest-app-v0.1:
Вы можете добавить несколько заголовков к своему запросу, вызвав несколько раз метод setRequestProperty() . Например, следующий фрагмент кода добавляет заголовок Accept и кастомный заголовок Contact-Me :
5. Чтение ответов
После того как вы передали все заголовки запросов, вы можете проверить, есть ли у вас валидный ответ, используя метод getResponseCode() объекта HttpURLConnection .
Если класс HttpURLConnection получает код ответа на перенаправление, например 301, он автоматически обрабатывает его и следует за перенаправлением. Поэтому, как правило, вам не нужно будет писать дополнительный код для проверки перенаправления.
В случае отсутствия ошибок вы можете теперь вызвать метод getInputStream() , чтобы получить ссылку на входящий поток соединения.
Большинство REST API в наши дни возвращают данные, отформатированные как документы JSON. Поэтому, вместо прямого чтения из объекта InputStream , я предлагаю вам создать для него InputStreamReader .
6. Разбор JSON ответов
Android SDK имеет класс JsonReader, который позволяет легко разбирать документы JSON. Вы можете создать новый экземпляр класса JsonReader , передав объект InputStreamReader его конструктору.
То как вы извлекаете определенную часть информации из документа JSON, зависит от его структуры. Например, документ JSON, возвращаемый корневой конечной точкой REST API GitHub, выглядит следующим образом:
Как вы можете видеть, ответ — это только один большой объект JSON, содержащий несколько ключей. Чтобы извлечь из него значение с именем organization_url, вам нужно будет написать следующий код:
Вышеупомянутый код обрабатывает ответ JSON как поток токенов. Поэтому он потребляет очень мало памяти. Однако, поскольку он должен обрабатывать каждый отдельный токен один за другим, он может оказаться медленным при обработке больших ответов.
После того как вы извлечете всю необходимую информацию, вы всегда должны вызвать метод close() для объекта JsonReader , чтобы он освобождал все сохраненные ресурсы.
Вы также должны закрыть соединение, вызвав метод disconnect() объекта HttpURLConnection .
7. Использование разных HTTP методов
HTTP-интерфейсы REST используют методы HTTP для определения типа операции, которая должна выполняться над ресурсом. На предыдущих шагах мы использовали метод HTTP GET для выполнения операции чтения. Поскольку класс HttpURLConnection использует по умолчанию метод GET , нам не нужно было его явно указывать.
Чтобы изменить метод HTTP вашего объекта HttpURLConnection , вы должны использовать его метод setRequestMethod() . Например, следующий фрагмент кода открывает соединение с конечной точкой, принадлежащей httpbin.org, и устанавливает свой HTTP-метод в POST :
Как вы уже знаете, POST -запросы используются для отправки данных на сервер. При записи в выходной поток соединения вы можете легко добавить любые данные в тело запроса POST . Однако, прежде чем вы это сделаете, вы должны убедиться, что вы вызываете метод setDoOutput() объекта HttpURLConnection и передаете ему значение true .
В следующем фрагменте кода показано, как отправить на сервер простую пару «ключ-значение»:
8. Кэширование ответов
Всегда рекомендуется кэшировать ответы HTTP. Таким образом, вы можете не только сократить потребление пропускной способности вашего приложения, но и сделать его более отзывчивым. Начиная с уровня API 13, Android SDK предлагает класс HttpResponseCache , который позволяет легко реализовать кэширование без каких-либо изменений в вашей сетевой логике.
Чтобы установить кэш для вашего приложения, вы должны вызвать метод install() класса HttpResponseCache . Метод ожидает абсолютный путь, указывающий, где должен быть установлен кеш, и число, определяющее размер кеша. Вы можете использовать метод getCacheDir() , если вы не хотите указывать абсолютный путь вручную.
В следующем фрагменте кода устанавливается кеш размером 100 000 байт:
Как только кеш установлен, класс HttpURLConnection начинает использовать его автоматически. Чтобы проверить, работает ли ваш кеш, вы можете использовать его метод getHitCount() , который возвращает количество HTTP-ответов, которые были отправлены из кеша.
Заключение
Существуют тысячи REST API-интерфейсов, которые вы можете свободно использовать в своих приложениях для Android. Используя их, вы можете сделать ваше приложение более информативным, интересным и многофункциональным. В этом уроке вы узнали, как использовать класс HttpURLConnection для использования таких REST API. Вы также узнали, как создать кеш ответов HTTP, который снижает использование потребление сетевого трафика вашим приложением.
Если вы считаете, что использование HttpURLConnection слишком сложное, вам следует обратить внимание на сторонние библиотеки, такие как например, Volley. Библиотеки, подобные этой, используют класс HttpURLConnection внутри, но предоставляют множество удобных методов, которые позволяют сделать ваш код более кратким и читаемым.
Чтобы узнать больше о работе с сетью на платформе Android, вы можете обратиться к руководству по сетевым операциям Android.
Источник
REST API на Java без фреймворков
Перевод статьи подготовлен специально для студентов курса «Разработчик Java».
В экосистеме Java есть много фреймворков и библиотек. Хотя и не так много, как в JavaScript, но они и не устаревают так быстро. Тем не менее, это заставило меня задуматься о том, что мы уже забыли, как писать приложения без фреймворков.
Вы можете сказать, что Spring — это стандарт и зачем изобретать велосипед? А Spark — это хороший удобный REST-фреймворк. Или Light-rest-4jis. И я скажу, что вы, конечно, правы.
Но вместе с фреймворком, помимо готовой функциональности, вы получаете много магии, сложности с изучением, дополнительные функции, которые вы, скорее всего, не будете использовать, а также баги. И чем больше стороннего кода в вашем сервисе, тем больше вероятность того, что у вас будут ошибки.
Сообщество open source очень активное, и есть большая вероятность, что ошибки в фреймворке будут быстро исправлены. Но все же, я хотел бы призвать вас подумать, действительно ли вам нужен фреймворк. Если у вас небольшой сервис или консольное приложение, возможно, вы сможете обойтись без него.
Что вы можете получить (или потерять), используя чистый Java-код? Подумайте об этом:
- ваш код может быть намного чище и понятнее (а может и в полном беспорядке, если вы плохой программист)
- у вас будет больше контроля над вашим кодом, вы не будете ограничены рамками фреймворка (хотя вам придется писать больше своего кода для функциональности, которую фреймворк предоставляет из коробки)
- ваше приложение будет развертываться и запускаться гораздо быстрее, потому что фреймворку не нужно инициализировать десятки классов (или не будет запускаться вообще, если вы перепутаете что-то, например, в многопоточности)
- если вы развертываете приложение в Docker, то ваши образы будут намного меньше, потому что ваши jar также будут меньше
Я провел небольшой эксперимент и попытался разработать REST API без фреймворка. Возможно, это будет интересно с точки зрения обучения и освежения знаний.
Когда я начал писать этот код, то часто сталкивался с ситуациями, когда отсутствовал функционал, который есть в Spring из коробки. В эти моменты, вместо того, чтобы взять Spring, надо было переосмыслить и разработать все самостоятельно.
Я понял, что для решения реальных бизнес-задач я, все же, предпочел бы использовать Spring, а не изобретать велосипед. Тем не менее, я считаю, что это упражнение было довольно интересным опытом.
Начинаем
Я буду описывать каждый шаг, но не всегда буду приводить полный исходный код. Полный код вы можете посмотреть в отдельных ветках git-репозитория.
Сначала создайте новый Maven-проект со следующим pom.xml .
Добавьте в зависимости java.xml.bind , потому что он был удален в JDK 11 (JEP-320).
и Jackson для JSON-сериализации
Для упрощения POJO-классов будем использовать Lombok:
и vavr для средств функционального программирования
Также создадим основной пустой класс Application .
Исходный код в ветке step-1.
Первый эндпоинт
В основе нашего веб-приложения будет класс com.sun.net.httpserver.HttpServer . И простейший эндпоинт (endpoint) /api/hello может выглядеть следующим образом:
Веб-сервер запускается на порту 8000 и предоставляет эндпоинт, который просто возвращает Hello. Это можно проверить, например, используя curl:
Исходный код в ветке step-2.
Поддержка разных HTTP-методов
Наш первый эндпоинт работает отлично, но вы можете заметить, что независимо от того, какой HTTP-метод использовать, он всегда отвечает одинаково.
Первое, что нужно сделать, это добавить код для различения методов, например:
Попробуйте еще раз такой запрос:
ответ будет примерно таким:
Есть также несколько моментов, которые нужно помнить. Например, не забыть сделать flush() для OutputStream и close() для exchange . При использовании Spring мне об этом даже не приходилось думать.
Исходный код в ветке step-3.
Парсинг параметров запроса
Парсинг параметров запроса — это еще одна «функция», которую нам нужно реализовать самостоятельно.
Допустим, мы хотим, чтобы наш hello api получал имя в параметре name , например:
Мы могли бы распарсить параметры следующим образом:
и использовать, как показано ниже:
Полный пример в ветке step-4.
Аналогично, если мы хотим использовать параметры в path. Например:
Чтобы получить элемент по нам нужно распарсить url самостоятельно. Это становится громоздким.
Безопасность
Часто нам нужно защитить доступ к некоторым эндпоинтам. Например, это можно сделать, используя базовую аутентификацию (basic authentication).
Для каждого HttpContext мы можем установить аутентификатор, как показано ниже:
Значение “myrealm” в конструкторе BasicAuthenticator — это имя realm. Realm — это виртуальное имя, которое может быть использовано для разделения областей аутентификации.
Подробнее об этом можно прочитать в RFC 1945.
Теперь вы можете вызвать этот защищенный эндпоинт, добавив заголовок Authorization :
Текст после «Basic» — это кодированный в Base64 текст admin:admin , который представляет собой учетные данные, жестко закодированные в нашем примере.
Для аутентификации в реальном приложении вы, вероятно, получите учетные данные из заголовка и сравните их с именем пользователя и паролем, хранящимися в базе данных.
Если вы не укажете заголовок, то API ответит статусом
Полный пример в ветке step-5.
JSON, обработка исключений и прочее
Теперь пришло время для более сложного примера.
Из моего опыта в разработке программного обеспечения наиболее распространенным API, который я разрабатывал, был обмен JSON.
Мы собираемся разработать API для регистрации новых пользователей. Для их хранения будем использовать базу данных в памяти.
У нас будет простой доменный объект User :
Я использую Lombok, чтобы избавится от бойлерплейта (конструкторы, геттеры).
В REST API я хочу передать только логин и пароль, поэтому я создал отдельный объект:
Объекты User создаются в сервисе, который будем использовать в обработчике API. Сервисный метод просто сохраняет пользователя.
В реальном приложении можно сделать больше. Например, отправлять события после успешной регистрации пользователя.
Реализация репозитория выглядит следующим образом:
Наконец, склеим все вместе в handle() :
Здесь JSON-запрос преобразуется в объект RegistrationRequest :
который позже я сопоставляю с объектом NewUser , чтобы сохранить его в базе данных и отправить ответ в виде JSON.
Также мне нужно преобразовать объект RegistrationResponse обратно в JSON-строку. Для этого используем Jackson
( com.fasterxml.jackson.databind.ObjectMapper ).
Вот как я создаю новый обработчик ( handler ) в main() :
Рабочий пример можно найти в ветке step-6. Там я также добавил глобальный обработчик исключений для отправки стандартных JSON-сообщений об ошибках. Например, если HTTP-метод не поддерживается или запрос к API сформирован неправильно.
Вы можете запустить приложение и попробовать один из следующих запросов:
- пример правильного запроса
Источник