БЛОГ ПРО WEB
Рассказываю о web-разработке
и помогаю создавать сайты
Простой API для Вашего сайта
Возникла ситуация, когда необходимо использовать 2 БД MySQL на разных серверах для снижения нагрузки.
1 БД для основных задач и 2 БД для хранения различной статистики по всем модулям. А Статистика, как всем известно, — это куча цифр, которыми не хочется засорять основную БД.
Так как решил использовать сторонний сервер, на ум приходит API. В принципе, для меня то, что нужно, так как возможно может пригодиться и для моих пользователей для вывода своей статистики на своих проектах.
Oauth использовать решил не стоит, да и было интересно как выйдет API своими руками.
API, ну или Парсер
Да, действительно, способ проще чем кажется. Можно данный способ организации назвать как Парсер, ведь будем использовать @file_get_contents()
Но мне важен результат!
Качаем исходники тут и разбираем что к чему
Собираем функционал API
У нас в итоге получится 2 части.
Файлы клиентской части
А теперь по порядку каждый файл
Клиентская часть
$url — это адрес к нашему серверу, а точнее к файлу api.php (о нем читать ниже).
Дальше мы отправляем запрос @file_get_contents($get); к серверу и получаем ответ с результатом в формате json_decode()
Начал с клиентской части потому что, мне кажется интереснее посмотреть что получится, а не то как это сделано. И поэтому, вот как использовать MySQL удаленно
Подключаем function.api.php на нужных страницах для связи с API сервера со статистикой к примеру.
А остальное все итак понятно. Там написал все 4 функции для примера, используя таблицу в бд следующего вида
И тут логично понятные параметры
query — запрос (SELECT, UPDATE, INSERT или DELETE)
table — таблица в бд (в моем случае ‘scripts’)
where — условия обычного формата (тут не стал что то изобретать. Типа, [id=5 OR >
values — и тут передаем параметры для добавления и редактирования в следующем формате
Мне кажется, просто и понятно…
Серверная часть API
Конечно же config.php
Проверка и отправка запроса в БД через класс API
Конечно как вы понимаете, проверка такого рода
лишь как пример. Тут надо делать проверку ключа и ID пользователя на соответствие. Тут проблем думаю не будет.
И файл class.a.php для разных запросов и возвращения результата
местами требуются некоторые проверки для защиты, но не критичны. Даю код, чтобы смысл был понятен. Дальше уже сами дорабатывайте)
Расписывать не буду, итак ясно что делает данный файл…
Простой RESTful-сервис на нативном PHP
Почти любой php-фреймворк умеет делать это из коробки. Например, Laravel, где роутинг реализован понятно и просто. Но что если нам не нужно прямо сейчас заниматься изучением новой большой темы, а хочется просто быстро завести проект с поддержкой REST API? Об этом и пойдет речь в статье.
Что должен уметь наш RESTful-сервис?
1. Поддерживать все 5 основных типов запросов: GET, POST, PUT, PATCH, DELETE.
2. Разруливать разнообразные маршруты вида
POST /goods
PUT /goods/
GET /users/
и прочие сколь угодно длинные цепочки.
Какой функционал мы будем поддерживать?
Для товаров возможности следующие:
По пользователям для разнообразия рассмотрим несколько вариантов с GET
Как это заработает на нативном PHP?
.htaccess
index.php
Рассмотрим index.php строка за строкой. Для начала получим метод запроса.
Затем данные из тела запроса
Теперь у нас есть все данные, нужно сделать с ними что-нибудь полезное. А сделают это всего лишь 4 строки кода
GET /goods/
В ответе клиенту мы выводим нужные данные: название товара и его цену. id товара и метод в реальном приложении совершенно не обязательны. Покажем их только, чтобы убедится, что вызывается нужный метод с правильными параметрами.
Давайте попробуем на примере: откройте консоль браузера и выполните код
В конце функции мы написали такой код.
По http-кодам ответов сервера
Мы не будем заморачиваться с выводом разных кодов, хотя по REST-у это и стоит делать. Клиентских ошибок много. Даже в нашем простом случае уместна 405 в случае неправильно переданного метода. Намеренно не хочу усложнять.
В случае успеха сервер у нас всегда вернет 200 ОК. По хорошему, при создании ресурса стоит отдавать 201 Created. Но опять-таки в плане упрощения эти тонкости мы отбросим, а в реальном проекте Вы их легко реализуете сами.
По совести говоря, статья закончена. Думаю, Вы уже поняли подход, каким образом разруливаются все маршруты, вынимаются данные, как это протестировать, как добавлять новые запросы и т.д. Но я для завершения образа приведу реализацию оставшихся 7 запросов, которые мы обозначили в начале статьи. Попутно приведу пару интересных замечаний, а в конце выложу архив с исходниками.
POST /goods
Добавление нового товара
PUT /goods/ PATCH /goods/
Частичное обновление товара
DELETE /goods/ GET /users/ GET /users//info
GET /users//info
Общая информация о пользователе
GET /users//orders
Получение списка заказов пользователя
Итоги и исходники
Делаем GraphQL API на PHP и MySQL. Часть 1: Установка, схема и запросы
В последнее время я все чаще и чаще слышу про GraphQL. И в интернете уже можно найти немало статей о том как сделать свой GraphQL сервер. Но почти во всех этих статьях в качестве бэкенда используется Node.js.
Я ничего не имею против Node.js и сам с удовольствием использую его, но все-таки большую часть проектов я делаю на PHP. К тому же хостинг с PHP и MySQL гораздо дешевле и доступнее чем хостинг с Node.js. Поэтому мне кажется не справедливым тот факт, что об использовании GraphQL на PHP в интернете практически нет ни слова.
В данной статье я хочу рассказать о том, как сделать свой GraphQL сервер на PHP с помощью библиотеки graphql-php и как с его помощью реализовать простое API для получения данных из MySQL.
Я решил отказаться от использования какого-либо конкретного PHP фреймворка в данной статье, но после ее прочтения вам не составит особого труда применить эти знания в своем приложении. Тем более для некоторых фреймворков уже есть свои библиотеки основанные на graphql-php, которые облегчат вашу работу.
Подготовка
В данной статье я не буду делать фронтенд, поэтому для удобного тестирования запросов к GraphQL серверу рекомендую установить GraphiQL-расширение для браузера.
Для Chrome это могут быть:
В таблице «users» будем хранить список пользователей:
А в таблице «friendships» связи типа «многие-ко-многим», которые будут обозначать дружбу между пользователями:
Дамп базы данных, как и весь остальной код, можно взять из репозитория данной статьи на Github.
Hello, GraphQL!
Для начала необходимо установить graphql-php в наш проект. Можно сделать это с помощью composer:
Теперь, по традиции напишем «Hello, World».
Для этого в корне создадим файл graphql.php, который будет служить конечной точкой (endpoint) нашего GraphQL сервера.
В нем подключим автозагрузчик composer:
Чтобы заставить GraphQL выполнить запрос необходимо передать ему сам запрос и схему данных.
Для получения запроса напишем следующий код:
Чтобы создать схему сначала подключим GraphQL\Schema:
Конструктор схемы принимает массив, в котором должен быть указан корневой тип данных Query, который служит для чтения данных вашего API, поэтому сначала создадим этот тип.
В простейшем случае тип данных Query должен быть экземпляром класса ObjectType, а его поля должны быть простых типов (например int или string), поэтому подключим классы предоставляющие эти типы данных в GraphQL:
И создадим тип данных Query:
Как можно заметить тип данных обязательно должен содержать имя (name) и массив полей (fields), а также можно указать необязательное описание (description).
Поля типа данных также должны иметь обязательные свойства «name» и «type». Если свойство «name» не задано, то в качестве имени используется ключ поля (в данном случае «hello»). Также в нашем примере у поля «hello» заданы необязательные свойства «description» — описание и «resolve» — функция возвращающая результат. В этом случае функция «resolve» просто возвращает строку «Привет, GraphQL!«, но в более сложной ситуации она может получать какую-либо информацию по API или из БД и обрабатывать ее.
Таким образом, мы создали корневой тип данных «Query», который содержит всего одно поле «hello», возвращающее простую строку текста. Давайте добавим его в схему данных:
А затем выполним запрос GraphQL для получения результата:
Остается только вывести результат в виде JSON и наше приложение готово:
Обернем код в блок try-catch, для обработки ошибок и в итоге код файла graphql.php будет выглядеть так:
Проверим работу GraphQL. Для этого запустим расширение для GraphiQL, установим endpoint (в моем случае это «localhost/graphql.php») и выполним запрос:
Вывод пользователей из БД
Теперь усложним задачу. Выведем список пользователей из базы данных MySQL.
Для этого нам понадобится создать еще один тип данных класса ObjectType. Чтобы не нагромождать код в graphql.php, вынесем все типы данных в отдельные файлы. А чтобы у нас была возможность использовать типы данных внутри самих себя, оформим их в виде классов. Например, чтобы в типе данных «user» можно было добавить поле «friends», которое будет являться массивом пользователей такого же типа «user».
Когда мы оформляем тип данных в виде класса, то не обязательно указывать у него свойство «name», потому что оно по умолчанию берется из названия класса (например у класса QueryType будет имя Query).
Теперь корневой тип данных Query, который был в graphql.php:
Будет находиться в отдельном файле QueryType.php и выглядеть так:
А чтобы в дальнейшем избежать бесконечной рекурсии при определении типов, в свойстве «fields» лучше всегда указывать не массив полей, а анонимную функцию, возвращающую массив полей:
При разработке проекта может появиться очень много типов данных, поэтому для них лучше создать отдельный реестр, который будет служить фабрикой для всех типов данных, в том числе и базовых, используемых в проекте. Давайте создадим папку App, а в ней файл, Types.php, который как раз и будет тем самым реестром для всех типов данных проекта.
Также в папке App создадим подпапку Type, в которой будем хранить все наши типы данных и перенесем в нее QueryType.php.
Теперь добавим пространство имен и заполним реестр Types.php необходимыми типами:
Пока в нашем реестре будет всего 2 типа данных: 1 простой (string) и 1 составной (query).
Теперь во всех остальных файлах вместо:
Подключим наш реестр типов:
И заменим все ранее указанные типы, на типы из реестра.
В QueryType.php вместо:
А схема в graphql.php теперь будет выглядеть так:
Чтобы получить пользователей из базы данных, необходимо обеспечить интерфейс доступа к ней. Получать данные из базы можно любым способом. В каждом фреймворке для этого есть свои инструменты. Для данной статьи я написал простейший интерфейс который может подключаться к MySQL базе данных и выполнять в ней запросы. Так как это не относится к GraphQL, то я не буду объяснять как реализованы методы в данном классе, а просто приведу его код:
В файле graphql.php добавим код для инициализации подключения к БД:
Теперь в папке Type создадим тип данных User, который будет отображать данные о пользователе. Код файла UserType.php будет таким:
Значение полей можно понять из их свойства «description». Свойства «id», «name», «email» и «countFriends» имеют простые типы, а свойство «friends» является списком друзей – таких же пользователей, поэтому имеет тип:
Необходимо также добавить в наш реестр пару базовых типов, которые мы раньше не использовали:
И только, что созданный нами тип User:
Возвращаемые значения (resolve) для свойств «friends» и «countFriends» берутся из базы данных. Анонимная функция в «resolve» первым аргументом получает значение текущего поля ($root), из которого можно узнать id пользователя для вставки его в запрос списка друзей.
В завершении изменим код QueryType.php так, чтобы в API были поля для получения информации о конкретном пользователе по его идентификатору (поле «user»), а также для получения списка всех пользователей (поле «allUsers»):
Тут чтобы узнать идентификатор пользователя, данные которого необходимо получить, у поля «user» мы используем свойство «args», в котором содержится массив аргументов. Массив «args» передается в анонимную функцию «resolve» вторым аргументом, используя который мы узнаем id целевого пользователя.
У аргументов могут быть свои свойства, но в этом случае я использую упрощенную форму записи массива аргументов, при которой ключи массива являются именами, а значения – типами аргументов:
Теперь можно запустить сервер GraphQL и проверить его работу таким запросом:
Заключение
На этом все. Читайте документацию. Задавайте вопросы в комментариях. Критикуйте.
Пишем свой 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
Создание «API-Centric» Web Application на PHP
Что такое “API-Centric” Web Application?
Это веб приложение которое большая часть функционала реализуется через API. Например: если вы авторизовываетесь, то вы отправляете свои данные через функции API, а API уже возвращает результат success или же ошибку. Другой характеристикой API является то что API не зависит от состояния пользователя.
Создавая приложения таким способом, мы можем воспользоваться им в различных средах и различными людьми. В этой статье мы создадим простое TODO приложение и клиентскую часть взаимодействующую с серверной. let’s begin!
Шаг 2. Создание API сервера
Создадим 2 проекта: API сервер (back end) и клиентскую часть (front end)
Создайте папку simpletodo_api и в ней создайте index.php файл. Он будет являться главным контроллером нашего API (front controller) так что все запросы к серверу API будет осуществляться через этот файл. Откройте его и вставьте следующий код:
Теперь добавим необходимый функционал действию action. Мы создаём метод createAсtion. Если вы в хорошем настроении то можете создать и для других действий функционал, я лишь предоставил интерфейс.
Создаём todoItem.php в моделях, чтобы мы могли создать код, реализующий «Создание пункта списка». Кстати говоря в данном примере – без БД (на файлах). Вы, конечно же можете не ограничиваться.
Congratulations! Мы успешно создали API server и сделали вызов API.
Шаг 3. Защищаем API server с app id и app secret.
Сейчас наш api server принимает все запросы. Мы должны ограничить доступ к серверу, чтобы гарантировать, что только наши собственные клиенты имеют возможность сделать API запросы. Так же вы можете создать систему в которой пользователи могут создавать свои собственные приложения, которые имеют доступ к API серверу, подобно тому, как работает Facebook и Twtter приложения.
Начнём с создание пары id-key для клиентов, которые буду использовать наш сервер. Так как это демо, мы можем использовать рандомную 32 символьную строку. Для APP ID, скажем ‘app001′.
Откройте index.php и измените его:
Здесь мы просто создаём новую сессию пользователя, основанную на введённом логине и пароле. Это действие является простой комбинацией ключа, по которому мы можем получить доступ к хранящимся TODO спискам. Далее перенаправление на todo.php для начала взаимодействия с api server’ом. Прежде чем создать todo.php давайте сначала определим класс ApiCaller, который инкапсулирует все методы вызова API, которые нам понадобится, включая шифрование запросов.
Создаём apicaller.php:
Это должно выглядеть так:
Приятно смотрится, неправда ли? Добавим теперь той самой функциональности, new_todo.php
Который содержит вызов todo/create, создавая новый TODO item элемент. Создание других страниц: (update_todo.php и delete_todo.php) должно быть простым.
Откроем new_todo.php:
Заключение:
Есть много преимуществ в разработке приложений, сделанных с API. Если вы хотите создать Android версию SimpleTODO, то вся функциональность, которая может вам потребоваться, уже есть в API server, так что все, что вам нужно сделать, это просто создать Android клиент! Хотите, реорганизовать или оптимизировать некоторые классы? Нет проблем — просто убедитесь, что выходные данные будут теми же. Нужно добавить больше функциональности? Вы можете сделать это без изменения кода клиента!
Вдохновением служила статья nettuts
Пишите если где ошибся, и комментарии по поводу где что лучше можно было бы сделать