php post запрос к api
Отправка POST запросов к API ONLYOFFICE
Потребовалось провести небольшую интеграцию проекта использующего REST API с решением на 1С. Опыта работы с REST API не было никакого, поэтому в ходе реализации интеграции столкнулся с небольшими трудностями которые в последствии успешно решил. Знания полученные по ходу проекта интеграции хорошо бы сохранить, так как они меют свойство быстро забываться при отсутствии практики, поэтому решил поделиться ими в блоге.
Итак для работы с API OnlyOffice нам нужно получить токен. Заголовок который мы должны послать серверу выгляит следующим образом.
где ourusername и yourpassword ваш логин и пароль соответственно.
Вообще получить токе можно воспользовавшись как функцией file_get_contents() так и с помощью curl. Рассмотрим первый вариант.
Тоже самое но с помощью curl выгдяти так:
Разумеется вместо адреса http://192.168.1.221/ выдолжны будете ввести свой.
Далее опишем пример из API создание пользователя.
Сначала вариант с file_get_contents(), отметим, что код нужно добавить к вышеприведенным в соответствии с используемым методом.
Теперь покажем как использовать метод curl
Мы сделали ни что иное как добавили в заголовок запроса наш токен.
Таким образом в случае успешного выполнения запроса вы получите в ответ JSON массив с параметрами созданного пользователя. Заметьте так же, что если пользователь с указанным e-mail уже создан, то будет вываливаться ошибка Internal server error 500.
Пишем свой API для сайта с использованием Apache, PHP и MySQL
С чего все началось
Разрабатывая проект, я столкнулся с необходимостью организации клиент-серверного взаимодействия приложений на платформах iOS и Android с моим сайтом на котором хранилась вся информация — собственно БД на mysql, картинки, файлы и другой контент.
Задачи которые нужно было решать — достаточно простые:
регистрация/авторизация пользователя;
отправка/получение неких данных (например список товаров).
И тут-то мне захотелось написать свой API для взаимодействия с серверной стороной — большей своей частью для практического интереса.
Входные данные
В своем распоряжении я имел:
Сервер — Apache, PHP 5.0, MySQL 5.0
Клиент — Android, iOS устройства, любой браузер
Я решил, что для запросов к серверу и ответов от него буду использовать JSON формат данных — за его простоту и нативную поддержку в PHP и Android. Здесь меня огорчила iOS — у нее нет нативной поддержки JSON (тут пришлось использовать стороннюю разработку).
Внешний вид запросов решено было сделать таким:
http://[адрес сервера]/[путь к папке api]/?[название_api].[название_метода]=[JSON вида <«Hello»:«Hello world»>]
Путь к папке api — каталог на который нужно делать запросы, в корне которого лежит файл index.php — он и отвечает за вызов функций и обработку ошибок
Название api — для удобства я решил разделить API группы — пользователь, база данных, конент и тд. В таком случае каждый api получил свое название
Название метода — имя метода который нужно вызвать в указанном api
JSON — строковое представление JSON объекта для параметров метода
Скелет API
Скелет API на серверной стороне состоит из нескольких базовых классов:
index.php — индексный файл каталога в Apache на него приходятся все вызовы API, он осуществляет парсинг параметров и вызов API методов
MySQLiWorker — класс-одиночка для работы с базой MySQL через MySQLi
apiBaseCalss.php — родительский класс для всех API в системе — каждый API должен быть наследован от этого класса для корректной работы
apiEngine.php — основной класс системы — осуществляет разбор переданных параметров (после их предварительного парсинга в index.php) подключение нужного класса api (через require_once метод), вызов в нем нужного метода и возврат результата в JSON формате
apiConstants.php — класс с константами для api вызовов и передачи ошибок
apitest.php — тестовый api для тестирования новых методов перед их включением в продакшн версию
Теперь подробней о каждом
Я попробовал достаточно документировать файлы, чтобы не занимать много место под текст. Однако в тех файлах где нет комментариев, я все ж приведу описание.
Index.php
Как уже говорил раньше это входной индексный файл для Apache а значит все вызовы вида www.example.com/api будет принимать он.
Первым делом устанавливаем тип контента — text/html (потом можно сменить в самих методах) и кодировку — UTF-8.
Дальше проверяем, что у нас что-то запрашивают. Если нет то выводим JSON c ошибкой.
Если есть параметры запроса, то подключаем файл движка API — apiEngine.php и создаем класс движка с переданными параметрами и делаем вызов api метода.
Выходим из цикла так как мы решили что будем обрабатывать только один вызов.
apiEngine.php
Вторым по важности является класс apiEngine — он представляет собой движок для вызова api и их методов.
apiConstants.php
Данный класс используется только для хранения констант.
MySQLiWorker.php
Класс-одиночка для работы с базой. В прочем это обычный одиночка — таких примеров в сети очень много.
apiBaseClass.php
Ну вот мы подошли к одному из самых важных классов системы — базовый класс для всех API в системе.
Как видно данный класс содержит в себе несколько «утилитных» методов, таких как:
конструктор в котором осуществляется соединение с базой, если текущее API собирается работать с базой;
деструктор — следит за освобождением ресурсов — разрыв установленного соединения с базой
createDefaultJson — создает дефолтный JSON для ответа метода
fillJSON — если подразумевается что запрос вернет только одну запись, то данный метод заполнит JSON для ответа данными из первой строки ответа от БД
Создадим свой API
Вот собственно и весь костяк этого API. Теперь рассмотрим как же это все использовать на примере создания первого API под названием apitest. И напишем в нем пару простых функций:
одну без параметров
одну с параметрами и их же она нам и вернет, чтобы было видно, что она их прочитала
одну которая вернет нам бинарные данные
И так создаем класс apitest.php следующего содержания
Для удобства тестирования методов, я дописываю к ним адрес по которому я могу сделать быстрый запрос для тестирования.
И так у нас три метода
helloAPI
Это простой метод без параметров. Его адрес для GET вызова www.example.com/api/?apitest.helloAPI=<>
Результатом выполнения будет вот такая страница (в браузере)
helloAPIWithParams
Этот метод принимает в параметры. Обязательным является TestParamOne, для него и сделаем проверку. Его его не передать, то будет выдан JSON с ошибкой
helloAPIResponseBinary
И последний метод helloAPIResponseBinary — вернет бинарные данные — картинку хабра о несуществующей странице (в качестве примера)
Как видно — здесь есть подмена заголовка для вывода графического контента.
Результат будет такой
Есть над чем работать
Для дальнейшего развития необходимо сделать авторизация пользователей, чтобы ввести разграничение прав на вызов запросов — какие-то оставить свободными, а какие-то только при авторизации пользователя.
Ссылки
Для тестирования выложил все файлы на github — simpleAPI
В данной статье вы узнаете, как создать простой REST API в PHP.
1. Обзор проекта
1.1 Что такое REST API?
REST API позволяет вашему приложению взаимодействовать с одним или несколькими различными приложениями, используя концепции REST.
1.2 Зачем нужен REST API?
Во многих приложениях REST API необходим, потому что это самый легкий способ создания, чтения, обновления или удаления информации между различными приложениями через Интернет или протокол HTTP. Эта информация представляется пользователю в одно мгновение, особенно если вы используете JavaScript для отображения данных на веб-странице.
1.3 Где используется REST API?
REST API может использоваться любым приложением, которое может подключаться к Интернету. Если данные из приложения могут быть созданы, прочитаны, обновлены или удалены с помощью другого приложения, это обычно означает, что используется REST API.
2. Файловая структура
3. Настройка базы данных
3.1 Создание таблицы категорий
3.2 Дамп данных для таблицы категорий
3.3 Создание таблицы товаров
3.4 Дамп данных для таблицы товаров
3.5 Подключение к базе данных
Приведенный ниже код показывает учетные данные базы данных и метод для получения подключения к базе данных с помощью PDO.
Создайте папку api и откройте её. Создайте папку config и в ней создайте файл database.php со следующим кодом.
4. Получение товаров
4.1 Создание объекта Product
Код ниже содержит класс с именем Product и несколько свойств. Также показан метод конструктора, который принимает соединение с базой данных.
4.2 Создание файла для чтения товаров
Код ниже содержит заголовки о том, кто может читать этот файл и какой тип содержимого он будет возвращать.
4.3 Подключение к базе данных и таблице товаров
Замените комментарий // подключение к базе данных будет здесь в файле read.php следующим кодом.
4.4 Чтение товаров из базы данных
Замените комментарий // чтение товаров будет здесь в файле read.php следующим кодом.
4.5 Создание метода read()
4.6 Уведомление пользователя о том, что товары не найдены
Замените комментарий // ‘товары не найдены’ будет здесь в файле read.php следующим кодом.
5. Создание товаров
5.1 Создание файла create.php
Откройте папку product и создайте в ней файл create.php со следующим содержимым.
5.2 Создание метода create()
6. Получение одного товара
6.1 Создание файла read_one.php
6.2 Создание метода readOne()
7. Обновление товара
7.1 Создание файла update.php
7.2 Создание метода update()
8. Удаление товара
8.1 Создание файла delete.php
Откройте папку product и создайте файл delete.php со следующим содержимым.
8.2 Создание метода delete()
9. Поиск товаров
9.1 Создание файла search.php
В папке product создайте файл search.php со следующим кодом.
9.2 Создание метода search()
10. Пагинация товаров
10.1 Создание файла read_paging.php
В папке product создайте файл read_paging.php со следующим кодом.
10.2 Создание файла core.php
Этот файл содержит нашу базовую конфигурацию, такую как базовый URL и переменные пагинации.
Откройте папку config и создайте в ней файл core.php со следующим содержимым.
10.3 Создание метода readPaging()
10.4 Создание метода count()
Так же в классе Product (файл product.php) добавьте метод count() для создания массива пагинации.
10.5 Получение массива пагинации
11. Получение категорий
11.1 Создание объекта Category
Откройте папку objects и создайте новый файл category.php со следующим кодом.
11.2 Создание файла read.php
Создайте новую папку category в корне, и в ней файл read.php со следующим кодом.
11.3 Создание метода read()
Если вам понравилась данная статья, рекомендую к прочтению создание регистрации и авторизации в php с использованием JWT.
Надеюсь, вам понравилась данная информация. Если вам интересна тема web-разработки, то можете следить за выходом новых статей в Telegram.
Отправка сообщений через API VK средствами PHP для ленивых
Что мы будем делать: настроим отправку сообщений от имени конкретного пользователя в несколько чатов и другим пользователям используя HTTP запрос средствами PHP, с минимальными усилиями.
Собственно, одними сообщениями мы не ограничимся. Все будет работать через standalone приложение vk по тому принципу, что мы потенциально сможем делать все действия, которые будут доступны этому самому пользователю (точнее все то, на что мы выдадим сами себе права, но об этом чуть позже).
Сообщения рассматриваем именно по той причине, что с ними можно работать только в standalone-приложениях.
План действий:
1. Создаем приложение
2. Получаем access_token
3. отправляем сообщения
1. Создаем приложение
Этот пункт делать под тем аккаунтом, к которому будет привязано приложение (Не обязательно тот же, с которого будут идти сообщения).
Имя пишем какое угодно — фигурировать оно нигде не будет.
Тип — Standalone-приложение.
Далее потребуется ввести код с смс-ки которая придет на привязанный к аккаунту номер. После ввода кода ничего не меняем в полях, идем в настройки и копируем ID приложения.
Больше тут можно ничего не трогать.
2. Используя ID и secret_key из приложения получаем access_token
access_token — строка из некоторого количества символов, которая будет отправляться с POST запросом для выполнения каких то функций. Собственно, к ней привязано, от имени какого пользователя будем действовать и что нам можно будет делать.
Для этого создаем на сайте страничку вот с таким кодом:
$client_id — собственно, ID нашего приложения из пункта 1.
$scope — список прав, которые мы можем делать от имени нашего пользователя. Конктерно, для нашей задачи подходит именно такой: возможность доступа в любое время (offline), и доступ к сообщениям (messages). Если надо больше, полный список тут. Можно выставлять либо битовой маской, либо перечислить названия.
Далее, важный момент: Заходим на нашу страничку с кнопкой, будучи залогованы в ВК под тем пользователем, от имени которого будем работать, и жамкаем по кнопочке. Появится подобный запрос:
Помимо пункта доступ к общей информации, все остальные пункты будут соответствовать списку разрешений, которые были переданы в scope. Жмем далее и видим следующее:
Красным выделен acces_token, ради которого весь второй пункт и писался.
3. HTTP запросами, передавая через POST параметры отправляем сообщения или используем любые другие методы API
Для нетерпеливых, проверить что все работает можно так:
Заменяем нули в конце на наш acces_token и переходим по этой ссылке в браузере.
Что произойдет:
Сообщение с текстом из параметра message будет отправлено пользователю c указанным user_id. (Если оставить как есть — придет мне. Я не обижусь).
Параметры получателя:
Полный список методов (при параметре scope=offline,messages) работать можно будет, соответственно только с разделом сообщений.
Ну и напоследок функция для отправки сообщения через POST. Простая, как автомат Калашникова — просто для наглядности:
Принципы построения REST JSON API
Эта памятка писалась для внутренних нужд (открыть глаза менее опытным в вебе коллегам). Но, т.к. я насмотрелся велосипедов от довольно уважаемых, казалось бы, контор, — выкладываю на хабр. Мне кажется, многим будет полезно.
Зачем
Надеюсь, читающий уже понимает, зачем ему вообще нужен именно REST api, а не какой-нибудь монстр типа SOAP. Вопрос в том, зачем соблюдать какие-то стандарты и практики, если браузеры вроде бы позволяют делать что хочешь.
Структура запросов и ответов
Любой http-запрос начинается со строки
где METHOD — это метод доступа (GET, PUT и т.д.), а URI — адрес запрашиваемого ресурса.
В начале запроса идут заголовки — просто текстовые строки вида key: value
Затем передаётся пустая строка, означающая конец секции заголовков, и затем — тело запроса, если оно есть.
В ответе сначала передаётся строка с версией http, кодом и строковым статусом ответа (например HTTP/1.1 200 OK ), далее текстовые заголовки ответа, потом пустая строка, потом тело ответа.
Тут вроде всё просто.
Кодирование запросов и ответов
Кодировка для всех и запросов, и ответов — UTF-8 и только UTF-8, т.к. некоторые, кхм, «браузеры» имеют привычку игнорировать содержимое заголовка charset.
Использование кодов символов и html-сущностей не допускается, т.е. режим JSON_UNESCAPED_UNICODE обязателен. Не все клиенты знают всю таблицу html сущностей (типа каких-нибудь ù ), да и при чём тут html. Не все клиенты готовы/хотят заниматься перекодированием \uXXXX; и &#XX;. Плюс возможны «весёлые» ситуации с избыточным экранированием или пропаданием слэшей и амперсандов.
Все данные, кроме URI и двоичных файлов, передаются в формате JSON. Обратите внимание, что далеко не всякий валидный javascript код является валидным JSON.
В частности, для строк используются только двойные кавычки. Одинарные кавычки в json-данных, хотя и допустимы в «обычном» javascript, могут вызвать непредсказуемые плохо отлавливаемые баги.
В запросах обязательно указывается заголовок
Вызовы к API отличаются от прочих вызовов (например, обычной загрузки html страницы по данному URI) именно по наличию application/json в Accept.
В ответах 2хх с непустым телом обязательно наличие заголовка ответа
При наличии тела запроса также обязателен заголовок запроса
либо, при загрузке файлов,
и далее, в первой части
после чего для каждого файла
Если вы используете защиту от CSRF (а лучше бы вам её использовать), то удобнее передавать CSRF-токен в отдельном заголовке (типа X-CSRF-Token) для всех запросов, а не внедрять вручную в каждый запрос. Хранить CSRF токен в куках плохо по той причине, что куки можно украсть, в чём собственно и состоит суть CSRF атаки.
Структура URI
Нагородить можно всякое, но лучшая практика — чтобы все URI имели вид
ну, или если у вас api лежит в какой-то папке,
Для разбора части URI до знака вопроса можно использовать регулярку
Ведущий слэш обязателен, т.к. неизвестно, с какого URL будет осуществлён запрос.
Методы HTTP
GET /:entity/:id — getById
В случае успеха сервер возвращает 200 OK с полями объекта в формате JSON в теле ответа (без дополнительного оборачивания в какой-либо объект)
В случае, если объект с такими id не существует, сервер возвращает 404 Not Found
В ответе обязательно должны быть заголовки, касающиеся политики кэширования, т.к. браузеры активно кешируют GET и HEAD запросы. При остутствии какой-либо политики управления кэшем должно быть:
GET /:entity[?param1=. ¶m2=. ] — списочный get
Простой случай: в случае успеха сервер возвращает 200 OK с массивом объектов в формате JSON в теле ответа (т.е. ответ начинается с [ и заканчивается ] ).
Если массив получился пустой, всё равно вовзращается 200 OK с пустым масивом [] в теле ответа.
Более сложный вариант: возвращается объект, в одном из полей которого — искомый массив. В остальных полях — данные о пагинации, фильтры, счётчики и пр. Только держите это консистентным по всем api.
HEAD /:entity[/:id] — запрос заголовков
Полный аналог GET с таким же URI, но не возвращает тело ответа, а только HTTP-заголовки.
Реализация поддержки HEAD запросов веб-сервером обязательна.
Активно используется браузерами в качестве автоматических pre-flight запросов перед выполнением потенциально опасных, по их мнению, операций. Например, браузер Chrome активно кидается head-запросами для получения политик CORS при кросс-доменных операциях (виджеты и пр). При этом ошибка обработки такого head-запроса приведёт к тому, что основной запрос вообще не будет выполнен браузером.
Может использоваться для проверки существования объекта без его передачи (например, для больших объектов типа мультимедиа-файлов).
POST /:entity — создаёт новый объект типа :entity
В теле запроса должны быть перечислены поля объекта в формате JSON без дополнительного заворачивания, т.е.
В случае успеха сервер должен возвращать 201 Created с пустым телом, но с дополнительным заголовком
указывающим на месторасположение созданного объекта.
Возвращать тело ответа чаще всего не требуется, так как у клиента есть все необходимые данные, а id созданного объекта он может получить из Location.
Также метод POST используется для удалённого вызова процедур (RPC), в этом случае ответ будет иметь статус 200 OK и результаты в теле. Вообще смешивать REST и RPC в одном api — идея сомнительная, но всякое бывает.
Единственный неидемпотентный некешируемый метод, т.е. повтор двух одинаковых POST запросов создаст два одинаковых объекта.
PUT /:entity/:id — изменяет объект целиком
В запросе должны содержаться все поля изменяемого объекта в формате JSON.
В случае успеха должен возвращать 204 No Data с пустым телом, т.к. у клиента есть все необходимые данные.
Идемпотентный запрос, т.е. повторный PUT с таким же телом не приводит к каким-либо изменениям в БД.
PATCH /:entity/:id — изменяет отдельные поля объекта
В запросе должны быть перечислены только поля, подлежащие изменению.
В случае успеха возвращает 200 OK с телом, аналогичным запросу getById, со всеми полями изменённого объекта.
Используется с осторожностью, т.к. два параллельных PATCH от двух разных клиентов могут привести объект в невалидное состояние.
DELETE /:entity/:id — удаляет объект, если он существует.
В случае успеха возвращает 204 No Data с пустым телом, т.к. возвращать уже нечего.
Идемпотентный запрос, т.е. повторный DELETE с таким же адресом не приводит к ошибке 404.
OPTIONS /:entity[/:id]
Получает список методов, доступных по данному URI.
Сервер должен ответить 200 OK с дополнительным заголовком
Некешиуремый необязательный метод.
Обработка ошибок
Возвращаемые ошибки передаются с сервера на клиент как ответы со статусами 4хх (ошибка клиента) или 5хх (ошибка сервера). При этом описание ошибки, если оно есть, приводится в теле ответа в формате text/plain (без всякого JSON). Соответственно, передаётся заголовок ответа
Использовать html для оформления сообщений об ошибках в api — так себе идея, будут проблемы журналированием и т.д. Предполагается, что клиент способен сам красиво оформить сообщение об ошибке для пользователя.
При выборе конкретных кодов ошибок не следует слишком увлекаться и пытаться применить существующие коды только потому, что название кажется подходящим. У многих кодов есть дополнительные требования к наличию определённых заголовков и специальная обработка браузерами. Например, код 401 запускает HTTP-аутентификацию, которая будет странно смотреться в каком-нибудь приложении на react или electron.
UPD по мотивам комментариев. Клиенты у вас будут разные: не только веб и мобильные приложения, но и такие штуки, как запускалка интеграционных тестов (CI), балансировщик нагрузки или система мониторинга у админов. Использование или неиспользование того или иного статуса ошибки определяется тем, будет ли он полезен хоть какому-то клиенту (т.е. этот клиент сможет предпринять какие-то действия конкретно по этому коду) и, наоборот, не будет ли проблем у какого-то из клиентов из-за неиспользования вами этого кода. Придумать реальный use-case, когда реакция клиента будет различаться в зависимости от 404 или 410, довольно сложно. При этом отличий 404 от 200 или 500 — вагон и телега.
400 Bad Request
Универсальный код ошибки, если серверу непонятен запрос от клиента.
403 Forbidden
Возвращается, если операция запрещена для текущего пользователя. Если у оператора есть учётка с более высокими правами, он должен перелогиниться самостоятельно. См. также 419
404 Not Found
Возвращается, если в запросе был указан неизвестный entity или id несуществующего объекта.
Списочные методы get не должны возвращать этот код при верном entity (см. выше).
Если запрос вообще не удалось разобрать, следует возвращать 418.
415 Unsupported Media Type
Возвращается при загрузке файлов на сервер, если фактический формат переданного файла не поддерживается. Также может возвращаться, если не удалось распарсить JSON запроса, или сам запрос пришёл не в формате JSON.
418 I’m a Teapot
Возвращается для неизвестных серверу запросов, которые не удалось даже разобрать. Обычно это указывает на ошибку в клиенте, типа ошибки при формировании URI, либо что версии протокола клиента и сервера не совпадают.
419 Authentication Timeout
Отправляется, если клиенту нужно пройти повторную авторизацию (например, протухли куки или CSRF токены). При этом на клиенте могут быть несохранённые данные, которые будут потеряны, если просто выкинуть клиента на страницу авторизации.
422 Unprocessable Entity
Запрос корректно разобран, но содержание запроса не прошло серверную валидацию.
Например, в теле запроса были указаны неизвестные серверу поля, или не были указаны обязательные, или с содержимым полей что-то не так.
Обычно это означает ошибку в введённых пользователем данных, но может также быть вызвано ошибкой на клиенте или несовпадением версий.
500 Internal Server Error
Возвращается, если на сервере вылетело необработанное исключение или произошла другая необработанная ошибка времени исполнения.
Всё, что может сделать клиент в этом случае — это уведомить пользователя и сделать console.error(err) для более продвинутых товарищей (админов, разработчиков и тестировщиков).
501 Not Implemented
Возвращается, если текущий метод неприменим (не реализован) к объекту запроса.
Ну вот, в общем-то, и всё. Спасибо за внимание!