> For the complete documentation index, see [llms.txt](https://prostokosaka.gitbook.io/bubble/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://prostokosaka.gitbook.io/bubble/95-primeri-i-rukovodstva.md).

# 9.5 Примеры и руководства

Так как Bubble API позволяет сторонним сервисам связываться с вашим приложением, реализация для каждого из них будет отличаться. Вот 3 примера использования Bubble API в реальных ситуациях.

## Уведомление пользователей об ошибке оплаты подписки через Stripe

Типичный вариант использования Bubble API - осуществление вашим приложением каких-либо действий в случае, когда что-то происходит на стороне другого сервиса. В нашем случае произойдет несколько шагов как на стороне Bubble, так и на стороне Stripe. Мы начнем с того, что у нас есть приложение, в котором уже установлен плагин Stripe с настроенными во вкладке Плагины ключами. Мы также предположим, что процессы оплаты сохраняют ID пользователя в Stripe в сущности пользователе, нам нужно, чтобы он из ID, предоставляемого Stripe, попал в сущность пользователя, чтобы получить его/её адрес электронной почты.

В данном примере мы предполагаем, что домен приложения

`https://stripeexample.bubbleapps.io`

Начнем со стороны Bubble. Нам нужно задать точку входа API, которая будет срабатывать при ошибке списания средств с карты. Этот API процесс должен содержать действие, отправляющее пользователю письмо с сообщением, предлагающим ему или ей обновить данные карты. Поэтому, давайте начнем с создания нового API события, которое назовем "chargefailed" (ошибкасписания).

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.28.00%20PM.png)

Мы создаем эту точку входа публичной, чтобы Stripe смог её запустить через webhook (см ниже), и для простоты сделаем возможным её запуск без аутентификации.

Посмотрев документацию (!!!ЛНК!!!) Stripe мы видим, что он посылает при срабатывании вебхука. Сервер Stripe делает запрос к нашей точке входа и посылает в теле запроса ID события. Поэтому мы добавляем параметр ID текстового типа к нашему вызову.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.36.01%20PM.png)Теперь мы можем начать создание действия "Послать Email"/"Send Email". Нам нужно сделать следующее:

1. Использовать действие Send Email для отправки пользователю письма.
2. Использовать ID, отправленный Stripe, для получения "объекта События"/"Event object" (!!!ЛНК!!!). Это событие содержит ID покупателя и объект оплаты.
3. Выполнить поиск по базе данных для того, чтобы получить пользователя с данным ID покупателя.
4. Написать дружелюбное напоминание.

Начнем с добавления действия и заполним поле "Кому"/"To". При этом, нам важно понять, что нам нужно и от этого строить дальнейшие действия. Поэтому, мы начнем с поиска пользователей, добавим ограничение по полю "ID покупателя"/"Customer ID" и в качестве значения зададим результат API вызова от Stripe. Вот такой будет поиск.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.43.23%20PM.png)Для получения ID покупателя из предыдущего события плагин Stripe предоставляет процедуру, которая извлекает "объект События"/"Event object" по "ID События"/"Event ID". При этом Stripe проверяет "ID События"/"Event ID" и возвращает "объект События"/"Event object". Из этого объекта вы можете получить ID Покупателя в Stripe. Итак, нам нужен источник данных "Получить Данные по API"/"Get Data from an API".

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.44.39%20PM.png)

API процедура называется "Get Stripe event", и нам нужно отправить именно тот event\_id, который был получен от Stripe с первоначальным запросом (вебхуком). Этот параметр является первым в выпадающем списке, выбираем его.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.46.06%20PM.png)

На этом этапе мы извлекли "объект События Stripe"/"Stripe Event object" , и нам нужно получить "ID Покупателя"/"Customer ID" и выражение для поиска будет готово.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.48.02%20PM.png)

Теперь мы можем вернуться к полю "Кому"/"To" действия Send Email и получить email пользователя. Обратите внимание, что поиск возвращает список пользователей. В данном случае мы знаем, что Customer ID уникален для каждого пользователя, но нам нужно получить первый элемент в списке, чтобы перейти от списка пользователей к конкретному пользователю, а затем получить его email.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.50.26%20PM.png)

Теперь мы можем завершить действие добавлением сообщения, которое хотим послать.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%201.51.23%20PM.png)

Мы настроили все на стороне Bubble. Подытожим, что делает наш процесс:

1. Получает ID События, посланный Stripe через вебхук.
2. Запрашивает Event object и получает Customer ID
3. Осуществляет поиск по базе дынных приложения и получает пользователя по этому Customer ID
4. Посылает email пользователю, которого нашел поиск.

Полный адрес для этого процесса, как описано в справочнике (!!!ЛНК!!!):

`https://stripeexample.bubbleapps.io/api/1.1/wf/chargefield`

Перейдем в Stripe для настройки вебхука. Что нам нужно? При ошибке оплаты, отправить вебхук по дынной ссылке. Это делается здесь (!!!ЛНК!!!).![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%202.02.21%20PM.png)Готово! При ошибке оплаты, отправляется вебхук, и Bubble посылает пользователю письмо. Исполнение такого процесса можно увидеть в Логах сервера (!!!ЛНК!!!).

## Еженедельная рассылка

Этот пример описывает создание системы, в которой пользователи могут включать и отключать еженедельную рассылку. Мы затронем логику и процессы для настройки еженедельного действия, а содержание письма трогать не будем.

Начнем с активации API для POST/Процессов (POST/Workflow API) для нашего приложения во вкладке Настройки. Обратите внимание, что для этого у вас должен быть платный тариф.

![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%202.53.55%20PM.png)

После этого перейдем на страницу API и создадим новое повторяющееся событие.![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%202.55.59%20PM.png)

Давайте назовем это событие "Newsletter" (Рассылка). Подписка на рассылку закрепляется за пользователем, поэтому выберем пользователя типом сущности.![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%202.57.34%20PM.png)У данного процесса будет одно действие, посылающее письмо пользователю, которого передали в этот процесс. ("Current Workflow User")![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%203.00.02%20PM.png)Теперь мы можем перейти на страницу нашего приложения, которая будет предлагать пользователям подписаться и отписаться от рассылки. Сделаем это на очень упрощенной странице "account", на которой есть две кнопки.![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%203.03.00%20PM.png)На этой странице нам нужно настроить два процесса. Мы предположим, что здесь пользователь уже вошел в систему и не будем беспокоиться о проверке этого на странице для примера.

Первый процесс будет подписывать пользователей. Он запускается, когда пользователь кликнул по кнопке "Opt-in", и использует действие "Set/Cancel a recurring event".![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%203.06.02%20PM.png)Это действие принимает в качестве параметров событие и сущность. В таком случае событие "Newsletter", а в качестве сущности "Current User". Процесс мы создаем для еженедельной рассылки, начиная с 9 утра следующего дня.![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%203.23.16%20PM.png)У процесса отписки та же самая структура, только в периодичности (Frequency) нужно поставить "none". Практически, этот процесс отменяет любое запланированное повторяющееся событие (и ничего не делает, если расписание пустое).![](https://manual.bubble.is/assets/Desktop%202017-03-16%20at%203.25.29%20PM.png)

## Создание скрипта для чтения данных из базы данных

API для GET/Данных позволяет читать данные программными методами. Это можно делать с помощью другого приложения, но также с помощью скриптов для сохранения или вывода данных на экран. Этот пример показывает, как это сделать на языке Python. Мы напишем этот скрипт для приложения, которое находится на домене yourapp.com и наша цель - получить все чеки. Это предполагает, что в нашем приложении есть тип с названием "invoice". Ограничений мы не добавляем, но это легко сделать, как описано в справочнике (!!!ЛНК!!!).

Ключевая идея в таком скрипте - разбивка на страницы (!!!ЛНК!!!). Когда вы делаете запрос по API, вам нужно задать, откуда начинать и сколько элементов запросить. Каждый ответ от GET API будет возвращать количество оставшихся элементов. В нашем примере нам нужно начать с увеличенного на один значения последнего элемента предыдущего вызова.

```
#packages to perform the request, handle JSON objects, and encode URLs
import requests
import json
import urllib

session = requests.Session()

#API KEY as defined in the settings tab, so that the script has full access to the data

API_KEY = 'XXXX'
#base endpoint, see https://bubble.is/reference#API.get_api.Endpoint
base_url = 'https://yourapp.com/api/1.1/obj/invoice'

#Query initial parameters. We do not send a limit parameter (default is 100)
cursor = 0
remaining = 100

#we keep making calls till we have no remaining items to fetch
while remaining > 0:    
    #data we send with the search. Search constraints would be here
    params = {'cursor': cursor, 'api_token': API_KEY}
    url = base_url +'?' + urllib.urlencode(params)
    response = session.get(url)

    if response.status_code != 200:
        print('Error with status code {}'.format(response.status_code))
        exit()

    chunk = response.json()['response']
    remaining = chunk['remaining']
    count = chunk['count']
    results = chunk['results']

    #we print each object
    for result in results:        
        print json.dumps(result, indent=4, sort_keys=True)

    cursor += count

print 'No more entries'
```

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