Как написать удобный API — 10 рекомендаций
Я разработчик и большую часть моей карьеры я строю API различных сервисов. Рекомендации для этой статьи были собраны на основе наиболее часто встречающихся проблем при проектировании своего сервиса в команде или использовании сторонних API.
Скорее всего, вы сталкивались с провайдерами ужасного API. Работа с ними, как правило, сопряжена c повышенной эмоциональностью и недопониманием. Большую часть таких проблем можно избежать, проектируя интерфейс приложения, используя советы ниже.
1. Не используйте глаголы в URL *
* — если это одна из CRUD-операций.
За действие с ресурсом отвечают CRUD-методы запроса: POST — создать (create), GET — получить (read), PUT/PATH — обновить (update), DELETE — удалить (ну вы поняли). Плохо:
POST /users//delete - удаление пользователя POST /bookings//update - обновление бронировки
Хорошо:
DELETE /users/ PUT /bookings/
2. Используйте глаголы в URL
Плохо:
POST /users//books//create - добавить книгу пользователю
Хорошо:
POST /users//books//attach POST /users//notifications/send - отправить уведомление пользователю
3. Выделяйте новые сущности
Выше есть пример добавления книги пользователю, возможно, логика вашего приложения подразумевает список избранного, тогда роут может быть и таким:
POST /wishlist//
4. Используйте один идентификатор ресурса *
* — если ваша структура данных это позволяет.
Это значит если у вас есть записи вида один ко многим, например
бронь -> путешественники (booking->travellers), вам будет достаточно передавать в запросе идентификатор путешественника.
Плохо:
# получение данных путешественника GET /bookings//travellers/
Хорошо:
GET /bookings/travellers/
Также замечу, что /bookings/travellers/ лучше, чем просто /travellers . Хорошо придерживаться иерархии данных в своем API.
5. Все ресурсы во множественном числе
Плохо:
GET /user/ - получение данных пользователя POST /ticket//book - бронирование билета
Хорошо:
GET /users/ POST /tickets//book
6. Используйте HTTP-статусы по максимуму
Самый простой способ обработки ошибок — это ответить соответствующим кодом состояния. В большинстве случает один этот статус может дать исчерпывающую информацию о результате обработки запроса. Одни из самых распространенных кодов ответов:
- 400 Bad Request — клиент отправил неверный запрос, например, отсутствует обязательный параметр запроса.
- 401 Unauthorized — клиенту не удалось пройти обязательную аутентификацию на сервере для обработки запроса.
- 403 Forbidden — клиент аутентифицирован, но не имеет разрешения на доступ к запрошенному ресурсу.
- 404 Not Found — запрошенный ресурс не существует.
- 409 Conflict — этот ответ отправляется, когда запрос конфликтует с текущим состоянием сервера.
- 500 Internal Server Error — на сервере произошла общая ошибка.
- 503 Service Unavailable — запрошенная услуга недоступна.
7. Модификаторы получения ресурса
Логика построения роутов может быть не связана с архитектурой проекта или структурой базы данных. Например, в бд есть викторины и пройденные викторины — две отдельные таблицы (quizzes и passed_quizzes). Но для апи это могут быть просто викторины, а пройденные викторины это модификатор.
Пример: /quizzes и /quizzes/passed . Здесь quizzes — ресурс (викторины), passed — модификатор (пройденные).
Плохо:
GET /passed-quizzes - получение пройденных викторин GET /booked-tickets - получение забронированных билетов POST /gold-users - создание премиум пользователя
Хорошо:
GET /tickets/booked POST /users/gold
8. Выберите одну структуру ответов
Когда на два запроса к API может быть получен совсем разный по структуре ответ — это грустно. Старайтесь сформировать одну четкую структуру, которой всегда будете придерживаться. Будет круто еще включить служебные поля, несущие дополнительную информацию.
Плохо:
GET /book/
Хорошо:
GET /book/ < "status": 0, "message": "ok", "data": >
В этом примере 3 поля универсальны и могут использоваться для любого ответа от апи. status , message — собственный статус и сообщение приложения по которому клиент сможет ориентироваться, эти поля сообщат ему дополнительную информацию о процессе обработки запроса, но не данные ресурса. Например, в нашем приложении в один момент времени, пользователь может проходить только одну викторину. Тогда запрос на начало новой может выдать 409-й статус, а в полях status и message — дополнительную информацию, почему была получена ошибка.
9. Все параметры и json в camelCase
9.1 В параметрах запросов
Плохо:
GET /users/ GET /users/ GET /users/
Хорошо:
GET /users/ POST /ticket//gold
9.2 В теле ответа или принимаемого запроса
Плохо:
Хорошо:
10. Пользуйтесь Content-Type
Плохо:
GET /tickets.json GET /tickets.xml
Хорошо:
GET /tickets // и в хедере Сontent-Type: application/json // или Сontent-Type: application/xml
Заключение
Перечисленные выше рекомендации это далеко не весь список способов сделать API лучше. Для дальнейшего изучения рекомендую разобрать спецификации REST API и список кодов http-статусов (вы удивитесь, насколько их много и какие ситуации они охватывают).
А в комментариях предлагаю написать свою рекомендацию по построению REST API, которую вы считаете важной.
Как сделать свое api
Используя Express и Node.js, мы можем реализовать полноценный API в стиле REST для взаимодействия с пользователем. Архитектура REST предполагает применение следующих методов или типов запросов HTTP для взаимодействия с сервером:
Зачастую REST-стиль особенно удобен при создании всякого рода Single Page Application, которые нередко используют специальные javascript-фреймворки типа Angular, React или Knockout.
Рассмотрим, как создать свой API. Для нового проекта создадим новую папку, которая пусть будет называться webapp . Сразу определим в проекте файл package.json :
В проекте нам понадобятся express для обработки запроса. Далее перейдем к этому каталогу в командной строке/терминале и для добавления пакета выполним команду:
npm install
В данном случае мы создадим экспериментальный проект, который будет хранить данные в файле json и который призван просто показать создание API в Node.js в стиле REST. А пока добавим в папку проекта новый файл users.json со следующим содержанием:
Для чтения и записи в этот файл мы будем использовать встроенный модуль fs. Для обработки запросов определим в проекте следующий файл app.js :
const express = require("express"); const fs = require("fs"); const app = express(); const jsonParser = express.json(); app.use(express.static(__dirname + "/public")); const filePath = "users.json"; app.get("/api/users", function(req, res)< const content = fs.readFileSync(filePath,"utf8"); const users = JSON.parse(content); res.send(users); >); // получение одного пользователя по id app.get("/api/users/:id", function(req, res) < const // получаем id const content = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(content); let user = null; // находим в массиве пользователя по id for(var i=0; i> // отправляем пользователя if(user) < res.send(user); >else < res.status(404).send(); >>); // получение отправленных данных app.post("/api/users", jsonParser, function (req, res) < if(!req.body) return res.sendStatus(400); const userName = req.body.name; const userAge = req.body.age; let user = ; let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); // находим максимальный id const o.id;>)) // увеличиваем его на единицу user.id = id+1; // добавляем пользователя в массив users.push(user); data = JSON.stringify(users); // перезаписываем файл с новыми данными fs.writeFileSync("users.json", data); res.send(user); >); // удаление пользователя по id app.delete("/api/users/:id", function(req, res) < const let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); let index = -1; // находим индекс пользователя в массиве for(var i=0; i < users.length; i++)< if(users[i].id==id)< index=i; break; >> if(index > -1) < // удаляем пользователя из массива по индексу const user = users.splice(index, 1)[0]; data = JSON.stringify(users); fs.writeFileSync("users.json", data); // отправляем удаленного пользователя res.send(user); >else < res.status(404).send(); >>); // изменение пользователя app.put("/api/users", jsonParser, function(req, res) < if(!req.body) return res.sendStatus(400); const userId = req.body.id; const userName = req.body.name; const userAge = req.body.age; let data = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(data); let user; for(var i=0; i> // изменяем данные у пользователя if(user) < user.age = userAge; user.name = userName; data = JSON.stringify(users); fs.writeFileSync("users.json", data); res.send(user); >else < res.status(404).send(user); >>); app.listen(3000, function()< console.log("Сервер ожидает подключения. "); >);
Для обработки запросов определено пять методов для каждого типа запросов: app.get()/app.post()/app.delete()/app.put()
Когда приложение получает запрос типа GET по адресу «api/users», то срабатывает следующий метод:
app.get("/api/users", function(req, res)< const content = fs.readFileSync(filePath,"utf8"); const users = JSON.parse(content); res.send(users); >);
В качестве результата обработки мы должны отправить массив пользователей, которые считываем из файла. Для упрощения кода приложения в рамкаха данного экспериментального проекта для чтения/записи файла применяются синхронные методы fs.readFileSync()/fs.writeFileSync() . Но в реальности, как правило, работа с данными будет идти через базу данных, а далее мы все это рассмотрим на примере MongoDB.
И чтобы получить данные из файла с помощью метода fs.readFileSync() считываем данные в строку, которую парсим в массив объектов с помощью функции JSON.parse() . И в конце полученные данные отправляем клиенту методом res.send() .
Аналогично работает другой метод app.get() , который срабатывает, когда в адресе указан id пользователя:
app.get("/api/users/:id", function(req, res) < const // получаем id const content = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(content); let user = null; // находим в массиве пользователя по id for(var i=0; i> // отправляем пользователя if(user) < res.send(user); >else < res.status(404).send(); >>);
Единственное, что в этом случае нам надо найти нужного пользователя по id в массиве, а если он не был найден, возвратить статусный код 404: res.status(404).send() .
При получении запроса методом POST нам надо применить парсер jsonParser для извлечения данных из запроса:
// получение отправленных данных app.post("/api/users", jsonParser, function (req, res) < if(!req.body) return res.sendStatus(400); const userName = req.body.name; const userAge = req.body.age; let user = ; let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); // находим максимальный id const o.id;>)) // увеличиваем его на единицу user.id = id+1; // добавляем пользователя в массив users.push(user); data = JSON.stringify(users); // перезаписываем файл с новыми данными fs.writeFileSync("users.json", data); res.send(user); >);
После получения данных нам надо создать новый объект и добавить его в массив объектов. Для этого считываем данные из файла, добавляем в массив новый объект и перезаписываем файл с обновленными данными.
При удалении производим похожие действия, только теперь извлекаем из массива удаляемый объект и опять же перезаписываем файл:
// удаление пользователя по id app.delete("/api/users/:id", function(req, res) < const let data = fs.readFileSync(filePath, "utf8"); let users = JSON.parse(data); let index = -1; // находим индекс пользователя в массиве for(var i=0; i < users.length; i++)< if(users[i].id==id)< index=i; break; >> if(index > -1) < // удаляем пользователя из массива по индексу const user = users.splice(index, 1)[0]; data = JSON.stringify(users); fs.writeFileSync("users.json", data); // отправляем удаленного пользователя res.send(user); >else < res.status(404).send(); >>);
Если объект не найден, возвращаем статусный код 404.
Если приложению приходит PUT-запрос, то он обрабатывается методом app.put() , в котором с помощью jsonParser получаем измененные данные:
app.put("/api/users", jsonParser, function(req, res) < if(!req.body) return res.sendStatus(400); const userId = req.body.id; const userName = req.body.name; const userAge = req.body.age; let data = fs.readFileSync(filePath, "utf8"); const users = JSON.parse(data); let user; for(var i=0; i> // изменяем данные у пользователя if(user) < user.age = userAge; user.name = userName; data = JSON.stringify(users); fs.writeFileSync("users.json", data); res.send(user); >else < res.status(404).send(user); >>);
Здесь также для поиска изменяемого объекта считываем данные из файла, находим изменяемого пользователя по id, изменяем у него свойства и сохраняем обновленные данные в файл.
Таким образом, мы определили простейший API. Теперь добавим код клиента. Итак, как установлено в коде, Express для хранения статических файлов использует папку public , поэтому создадим в проекте подобную папку. В этой папке определим новый файл index.html , который будет выполнять роль клиента. В итоге весь проект будет выглядеть следующим образом:
Далее определим в файле index.html следующий код:
Список пользователей Список пользователей
| Id | Имя | возраст |
|---|
Основная логика здесь заключена в коде javascript. При загрузке страницы в браузере получаем все объекты из БД с помощью функции GetUsers:
async function GetUsers() < // отправляет запрос и получаем ответ const response = await fetch("/api/users", < method: "GET", headers: < "Accept": "application/json" >>); // если запрос прошел нормально if (response.ok === true) < // получаем данные const users = await response.json(); let rows = document.querySelector("tbody"); users.forEach(user =>< // добавляем полученные элементы в таблицу rows.append(row(user)); >); > >
Для добавления строк в таблицу используется функция row() , которая возвращает строку. В этой строке будут определены ссылки для изменения и удаления пользователя.
Ссылка для изменения пользователя с помощью функции GetUser() получает с сервера выделенного пользователя:
async function GetUser(id) < const response = await fetch("/api/users/" + id, < method: "GET", headers: < "Accept": "application/json" >>); if (response.ok === true) < const user = await response.json(); const form = document.forms["userForm"]; form.elements["id"].value = user.id; form.elements["name"].value = user.name; form.elements["age"].value = user.age; >>
И выделенный пользователь добавляется в форму над таблицей. Эта же форма применяется и для добавления объекта. С помощью скрытого поля, которое хранит id пользователя, мы можем узнать, какое действие выполняется — добавление или редактирование. Если id равен 0, то выполняется функция CreateUser, которая отправляет данные в POST-запросе:
async function CreateUser(userName, userAge) < const response = await fetch("api/users", < method: "POST", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); reset(); document.querySelector("tbody").append(row(user)); >>
Если же ранее пользователь был загружен на форму, и в скрытом поле сохранился его id, то выполняется функция EditUser, которая отправляет PUT-запрос:
async function EditUser(userId, userName, userAge) < const response = await fetch("api/users", < method: "PUT", headers: < "Accept": "application/json", "Content-Type": "application/json" >, body: JSON.stringify(< id: userId, name: userName, age: parseInt(userAge, 10) >) >); if (response.ok === true) < const user = await response.json(); reset(); document.querySelector("tr[data-rowid='" + user.id + "']").replaceWith(row(user)); >>
Хочу сделать API, с чего начать?
Хочу сделать рест апи (php + mysql), опыта в создании апи вообще нет. Допустим есть мобилка, какая будет общаться с сервером через апи, и стоит цель сделать хорошее, рест апи.
Вопросы следующие:
1) стоит ли делать апи с помощью какого то фреймворка, или с нуля?
2) надо выделять отдельный сервер для апи, или просто папочку в проекте назвать api, и туда все файлы связанные с ним положить?
3) хорошие примеры, литература, кто что может посоветовать. Когда ввожу rest api php выдаются пару уроков, но это не совсем то, что мне надо) нужны бест практис различные
- Вопрос задан более трёх лет назад
- 23633 просмотра
1 комментарий
Простой 1 комментарий

Для начала хотелось бы уточнить пару вопросов:
— а что у вас сейчас есть — у вас есть сайт, или может быть мобильное приложение?
— а на каком языке вы собираетесь писать api?
— а для чего вы пишете api и кто его собирается использовать?
Решения вопроса 0
Ответы на вопрос 7

Следует начать с проектирования API. Возмите https://swagger.io/ и набросайте все, что нужно.
Swagger вам позволяет объединить роутинг, документацию и примеры вызовов в единое целое.
Кроме этого он позволяет сгенерировать заглушки для разных языков программирования и фреймворков.
В принципе вы можете найти значительное количество интеграций для разных фреймоворков.
В целом API лучше делать с помощью фреймворков, поскольку в них уже реализованы тривиальные моменты по безопасности, аутентификации и авторизации. Вы можете использовать микрофреймворки, например тот же Slim. Вы даже можете сгенерировать роутинг для него используя генератор от Swagger.
В REST есть 6 принципов, прекрасно изложенных в Wiki. В REST нет ничего сложного и особенного. Это просто надстройка над стандартным протоколом HTTP. Именно поэтому нет никаких особенных уроков. Изучите работу HTTP и вы поймете как работает веб в целом и REST в частности.
По поводу отдельного сервера для API. Есть множество разных подходов. В последнее время все более актуальными становятся Serverless-приложения. Serverless архитектура идеально вписывается в REST. Но думаю для вас это пока рановато и сложновато. Слишком много для начала.
Логичнее всего держать проект в моно-репозитарии, если он не будет большим. Если вы точно не знаете насколько большим он будет, то можно разбить проект на компоненты и использовать Composer для управления зависимостями (советую полность прочитать эту страницу от корки до корки).
По поводу best practices есть очень хороший ресурс https://12factor.net/ru/
Он в целом применяется для всех приложений.
Запомните: первый блин всегда комом. Прочитайте все ресурсы, которые я привел для вас. В них много ссылок на другие, походите по ним, присмотритесь. Напишите первую версию API так, как вам кажется удобно. Постарайтесь применить практики из статей.
Вам нужен опыт и вы его не наберетесь, пока не сделаете что-то сами. Вы можете потратить год на чтение, но останетесь на том же месте, с которого начали. А другой человек напишет на коленке API за неделю, а потом перепишет его 20 раз за год и он вам расскажет в 10 раз больше, чем то, что вы изучили за год.
Дерзайте!
Как создать API без кода
В данной статье мы покажем как работать с API на нашей no-code платформе уровня pro, AppMaster.io. Но, для начала, напомним немного базовой информации про API.
Вводная информация
API означает Application Programming Interface, программный интерфейс приложения. Это способы, с помощью которых клиент и сервер могут взаимодействовать друг с другом. Клиент и сервер отправляют запросы и ответы, а API выступает посредником между ними.
Важно, чтобы взаимодействие сервера и клиента было легким, понятным и удобным. Это упрощает задачу как разработчиков (не нужно заново изобретать новый сервис), так и пользователей (сервис проще освоить, если он работает по знакомому принципу). Существует несколько видов API:
- Web service APIs, XML-RPC, and JSON-RPC, SOAP;
- WebSockets APIs;
- Library-based APIs, Java Script;
- Class-based APIs, C# API, Java.
На no-code платформе AppMaster.io используется стиль REST API.
REST или целиком Representational State Transfer — архитектурный стиль взаимодействия (обмена информацией) между клиентом и сервером. Сервисы в REST API взаимодействуют по протоколу HTTP.
Стиль REST обладает определенными преимуществами. Главное преимущество REST — большая гибкость. REST состоит из простых рекомендаций, давая возможность разработчикам реализовывать требования в своем формате. REST имеет высокую производительность, что очень важно, например, для быстрой загрузки на мобильных устройствах. Именно поэтому все крупные компании такие, как Twitter и Google, уже давно внедрили REST API для своих продуктов. Более детально про работу и главные преимущества REST API вы можете прочитать в нашей статье.
Структура любого запроса включает в себя пять основных компонентов: HTTP метод, эндпоинты, заголовки и тело, параметры запроса.
В REST API используются 4 основных HTTP-метода для работы с ресурсом (информацией) и каждый из них описывает, что должно быть сделано с ресурсом:
- POST — создание ресурса;
- GET — получение ресурса;
- PUT — обновление ресурса;
- DELETE — удаление ресурса.
Ресурс — это любой вид информации (документ, изображение, видео, текст и так далее). На no-code платформе AppMaster.io эта информация доставляется клиенту в нескольких форматах, в том числе, и в самом распротраненнеом — JSON.
Эндпоинт содержит URI — Uniform Resource Identifier (унифицированный идентификатор ресурса), который указывает, где и как найти ресурс в Интернете и включает в себя URL (URL или Uniform Resource Location является полноценным веб-адресом).
В заголовках передается информация как к клиенту, так и к серверу. Главным образом, заголовки предоставляют аутентификационные данные: API ключ, название или IP адрес компьютера, на котором установлен сервер, а также информацию о формате ответа.
Тело необходимо для передачи серверу дополнительной информации: данные тела запроса — это данные, которые вы, например, хотите добавить или заменить.
Документация по API для вашего приложения на нашей платформе создается автоматически и сохраняется в формате OpenAPI (Swagger) в его серверной части.
Вам не нужно специально разбираться, чтобы освоить создание API на AppMaster.io — вы поймете основные принципы, изучив инструменты платформы. Кроме того, основную часть API создает сам AppMaster.io — большинство настроек делается по умолчанию или при подключении модулей. Например, наш модуль предоставляет инструменты для интеграции с API для почтовых рассылок.
Попробуйте no-code платформу AppMaster
AppMaster поможет создать любое веб, мобильное или серверное приложение в 10 раз быстрее и 3 раза дешевле
Вам потребуется вручную ввести крошечные изменения в некоторые настройки API при интеграции (подключении) вашего приложения к другим приложениям или внешним ресурсам. Далее мы рассмотрим, как это можно сделать.
Создание API на no-code платформе AppMaster.io
Итак, настройки API вы можете найти в нескольких местах на нашей платформе.
Как создать API Эндпоинт на no-code платформе AppMaster.io
Зайдите в ваш аккаунт, в существующий проект.
Зайдите в Data Model Designer. В нем вы увидите модели с данными, которые хотите обработать с помощью API Эндпоинтов. В каждом проекте на старте всегда по умолчанию есть одна модель — User (Пользователь). Если вы находитесь в новом проекте и у вас еще нет своих моделей, создайте их.
Назначьте связи между вашими моделями и сохраните проект.
Зайдите в раздел Эндпоинты в левом меню экрана.
Здесь вы увидите список всех ваших Эндпоинтов и доступных для них методов REST API, подключенных к каждой модели на поле проекта. Вы сможете удалить ненужные методы и изменить их настройки (значок Шестеренки и значок Корзины).
Если в списке нет подходящего Эндпоинта, вы можете создать новый, нажав на кнопку New Endpoint и выбрав подходящий тип. Откроется модальное окно с настройками Эндпоинта.
Как создать внешний API на no-code платформе AppMaster.io
Зайдите в раздел Business Logic в левом меню.
Здесь вы можете создать внешний API запрос во вкладке External API Request (данная опция находится на стадии бета-тестирования).
Кроме того, как мы и упоминали выше, вся документация формируется автоматически и сохраняется в формате OpenAPI (Swagger) в серверной части вашего приложения.
Но Swagger — это не только документация, а, также, возможность протестировать все Эндпойнты прямо на месте, без использования каких-либо сторонних приложений (например, можно обойтись без Postman).
Итоги
Как видите, создавать и менять настройки API с помощью no-code совсем просто и занимает минимум времени. Если у Вас еще нет аккаунта на AppMaster.io — присоединяйтесь к нам и подключайте пробную версию.
