Статьи

Подключение к Jawbone UP API с помощью Node.js

Как разработчик, я не могу не получить доступ к огромному количеству данных о количестве шагов и привычках сна, которые есть у меня в Jawbone UP . Там так много данных! Поэтому я начал изучать, как получить эти данные, используя Jawbone UP API и Node.

Я нашел примеры того, как работать с Jawbone UP API и Node по всему Интернету, но все они были достаточно вовлечены и имели много движущихся частей, а также некоторые устаревшие модули (например, старые версии Express). В этой статье я хочу сосредоточиться на абсолютных основах — не беспокоясь о сохранении пользовательских данных в базе данных, создании учетных записей или подключении социальных логинов. Мы сосредоточимся на основных вещах, которые вам необходимо знать, чтобы заставить сервер Node проходить аутентификацию с помощью Jawbone API и возвращать пользовательские данные.

Весь код для этой демонстрации доступен на нашем репозитории GitHub .

Настройка приложения Jawbone

Первое, что нам нужно, это новое приложение Jawbone, настроенное под нашей учетной записью Jawbone. Это приложение, которое пользователи будут авторизовать для доступа к своим данным.

Начните с входа в раздел для разработчиков на сайте Jawbone, перейдя по ссылке https://jawbone.com/up/developer и нажав ссылку «Войти» в левом нижнем углу. Вам не понадобится конкретная учетная запись разработчика Jawbone, так как они позволят вам войти в систему, используя существующую учетную запись Jawbone.

The Jawbone Developer Войти

После входа перейдите на страницу https://jawbone.com/up/developer/account или нажмите ссылку «Управление учетной записью» в левом меню в разделе «Учетная запись».

Управлять счетом

На этой странице вы перейдете на страницу своего аккаунта разработчика. Отсюда нажмите «Создать приложение».

Страница учетной записи разработчика

На странице загрузки вам будет предложено ввести данные вашего приложения:

  • Имя — название вашей заявки, я ввел «Jawbone UP Node Demo».
  • Описание — это краткое описание, которое появится в пользовательской галерее приложений UP.
  • Подробное описание — оно отображается на странице сведений о приложении в галерее приложений.
  • Логотип — загрузите логотип для вашего приложения. Если вы получите сообщение об ошибке «Выбрать» (странно, я знаю, но это будет иметь смысл для тех немногих людей, которые подписались и получили это сообщение), скорее всего, изображение вашего логотипа слишком велико.
  • URL — домашняя страница вашего приложения
  • URL авторизации — URL, по которому будет найдена ваша страница входа. Для наших тестовых целей введите в https://localhost:5000/login/jawbone .
  • OAuth Redirect URI — URL-адреса, на которые вашему приложению разрешено перенаправлять после аутентификации пользователя. В нашем демо мы введем https://localhost:5000 .

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

Недавно созданное приложение

Обратите внимание на «Client Id» и «App Secret» — это то, что вам нужно для подключения к Jawbone API.

Начиная наше приложение Node

Я server.js весь наш код сервера Node в один файл с именем server.js . Начнем с того, что нам потребуются необходимые модули npm для нашего сервера.

Сначала мы настроили базовое приложение Express .

 var express = require('express'), app = express(), 

Затем нам требуется ejs (встроенный JavaScript), который позволяет нам вставлять JavaScript в наши HTML-шаблоны. Мы будем использовать это для отображения переменных JavaScript в нашем возвращенном HTML.

 ejs = require('ejs'), 

Чтобы иметь возможность проходить аутентификацию с помощью API Jawbone и перенаправлять обратно в наше приложение, Jawbone требует, чтобы мы перенаправили на страницу через https. Чтобы сделать это, мы должны включить https .

 https = require('https'), 

Далее мы включаем fs , что позволяет нам читать файловую систему. Нам нужно это прочитать файлы сертификатов сервера, чтобы включить https.

 fs = require('fs'), 

Нам также понадобится body-parser чтобы мы могли обрабатывать запросы JSON:

 bodyParser = require('body-parser'), 

Jawbone UP API использует протокол OAuth 2.0 для аутентификации. По сути, это означает, что для того, чтобы пользователь вошел в систему со своей учетной записью Jawbone и дал нам разрешение на доступ к своим данным, нам нужно пройти этот протокол. К счастью, модуль passport-oauth passport содержит модуль под названием passport-oauth который поддерживает это. Мы настроили passport в нашем приложении вместе с OAuth 2.0 следующим образом:

 passport = require('passport'), JawboneStrategy = require('passport-oauth').OAuth2Strategy, 

Затем мы получили понятную переменную, которая хранит порт, на котором мы будем работать.

 port = 5000, 

Далее мы будем хранить все значения, необходимые для аутентификации в Passport и OAuth 2.0, внутри jawboneAuth . В этот момент вы будете использовать значения «Client Id» и «App Secret», которые мы отметили ранее, когда регистрировали наше приложение.

 jawboneAuth = { clientID: 'jUvu1_4u_mA', clientSecret: '8961265d16ac678948006c2944ed85dbeeaab547', authorizationURL: 'https://jawbone.com/auth/oauth2/auth', tokenURL: 'https://jawbone.com/auth/oauth2/token', callbackURL: 'https://localhost:5000/sleepdata' }, 

Вот обзор того, что означают эти значения и / или откуда они пришли:

  • clientID — это «Client Id», указанный для вашего приложения Jawbone.
  • clientSecret — это значение «Секрет приложения» под ним.
  • authorizationURL — это местоположение страницы аутентификации UP OAuth 2.0, на которую будет перенаправлен пользователь.
  • tokenURL — это URL в Jawbone UP API, к которому мы должны обратиться по HTTPS, чтобы запросить токен доступа. Этот токен — это то, что нам нужно включить в наши вызовы Jawbone UP API, чтобы доказать, что мы уполномочены делать эти запросы данных. В Jawbone UP API этот токен длится год, так что вы можете сохранить его в базе данных и подключить пользователя к своей учетной записи Jawbone в течение года, прежде чем потребуется повторная аутентификация. Мы не будем рассматривать хранение пользователей и тому подобное в этом уроке, но хорошо иметь в виду, если вы хотите продвинуться дальше.
  • callbackURL — URL на нашем сайте, на который Jawbone направит пользователя обратно, как только он успешно предоставит нам доступ к своим данным. Для нас это страница для отображения данных сна.

Последняя переменная, которую мы должны определить, это наши sslOptions которые содержат все детали, которые мы должны предоставить нашему серверу, чтобы позволить нам запускать этот сервер с использованием HTTPS. Я подробно остановлюсь на каждом из них позже в этой статье, когда объясню, как мы настраиваем HTTPS.

Затем мы включаем несколько строк, определяющих некоторые основные функциональные возможности приложения Node, которые будут знакомы разработчикам Node:

 app.use(bodyParser.json()); app.use(express.static(__dirname + '/public')); app.set('view engine', 'ejs'); app.set('views', __dirname + '/views'); 
  • bodyParser — позволяет нам анализировать объекты JSON.
  • Папка Static — определяет, где наши статические файлы, такие как изображения, будут на сервере (в нашем случае, папка /public ).
  • EJS — назначает модуль ejs как наш шаблонизатор.
  • Папка Views — определяет, где будут находиться наши ejs представлений ejs на сервере (в нашем случае, папка /views ).

Чтобы инициализировать Passport в Express, мы запускаем следующую строку:

 app.use(passport.initialize()); 

Как примечание, в Passport можно настроить больше, если мы хотим иметь постоянные сеансы входа в систему. В этом случае нам необходимо настроить сеансы. Однако в этом руководстве мы сосредоточимся только на начальном этапе получения данных из API-интерфейса Jawbone UP и не будем беспокоиться о сеансах входа в систему.

Настройка наших запросов GET

Чтобы направить пользователя на экран входа в систему для Jawbone UP API, нам нужно назначить URL-адрес на нашем сервере, который будет перенаправлять на экран входа в систему Jawbone. Приведенный ниже код назначает URL /login/jawbone для этой цели. При запросе GET на этот URL мы вызываем passport.authorize() чтобы открыть нашу страницу авторизации Jawbone UP:

 app.get('/login/jawbone', passport.authorize('jawbone', { scope: ['basic_read','sleep_read'], failureRedirect: '/' }) ); 

Как вы можете видеть выше, у нас есть массив определенных разрешений, которые мы запрашиваем — ['basic_read','sleep_read'] . В нашем случае мы запрашиваем базовые данные пользователя и данные сна. Если вы хотите запросить доступ к количеству шагов, потребляемых блюд и т. Д., Вы можете добавить дополнительные запросы на разрешение в этот массив. Вы можете увидеть список того, что доступно и к чему они предоставляют доступ, на странице документации Jawbone UP Developer Authentication .

Также обратите внимание, что в случае сбоя аутентификации на экране аутентификации Jawbone UP он перенаправит нас на домашнюю страницу. В модуле passport можно установить successRedirect , однако я обнаружил, что с Jawbone UP API это не нужно, поскольку мы определим наш URL обратного вызова в JawboneStrategy далее в этом коде.

Затем мы настраиваем запрос GET, на котором будут отображаться наши данные сна. Это место, куда мы будем указывать API, чтобы перенаправить нас, когда мы получим доступ к пользовательским данным. В этом примере это /sleepdata :

 app.get('/sleepdata', passport.authorize('jawbone', { scope: ['basic_read','sleep_read'], failureRedirect: '/' }), function(req, res) { res.render('userdata', req.account); } ); 

У нас есть та же функция passport.authorize() , чтобы проверить, что пользователь вошел в систему к тому времени, когда он достигнет этой страницы. Если это так, мы запускаем res.render('userdata', req.account); который передает данные, которые Jawbone UP API возвратил в шаблон userdata.ejs (который мы скоро настроим). Если они не вошли в систему, они будут перенаправлены обратно на экран аутентификации Jawbone UP.

Затем мы устанавливаем URL-адрес, чтобы пользователь мог выйти из системы /logout , что перенаправляет пользователя на домашнюю страницу после выхода из системы:

 app.get('/logout', function(req, res) { req.logout(); res.redirect('/'); }); 

Наконец, для нашей маршрутизации мы устанавливаем его для загрузки нашего шаблона index.ejs если кто-то пытается получить доступ к домашней странице:

 app.get('/', function(req, res) { res.render('index'); }); 

Использование паспорта для подключения к Jawbone UP API

Самый большой кусок кода также является самым важным — настройка «стратегии» Passport, чтобы сообщить Passport, как обрабатывать запросы на авторизацию, используя 'jawbone' . Это выглядит так:

 passport.use('jawbone', new JawboneStrategy({ clientID: jawboneAuth.clientID, clientSecret: jawboneAuth.clientSecret, authorizationURL: jawboneAuth.authorizationURL, tokenURL: jawboneAuth.tokenURL, callbackURL: jawboneAuth.callbackURL }, function(token, refreshToken, profile, done) { var options = { access_token: token, client_id: jawboneAuth.clientID, client_secret: jawboneAuth.clientSecret }, up = require('jawbone-up')(options); up.sleeps.get({}, function(err, body) { if (err) { console.log('Error receiving Jawbone UP data'); } else { var jawboneData = JSON.parse(body).data; for (var i = 0; i < jawboneData.items.length; i++) { var date = jawboneData.items[i].date.toString(), year = date.slice(0,4), month = date.slice(4,6), day = date.slice(6,8); jawboneData.items[i].date = day + '/' + month + '/' + year; jawboneData.items[i].title = jawboneData.items[i].title.replace('for ', ''); } return done(null, jawboneData, console.log('Jawbone UP data ready to be displayed.')); } }); })); 

Давайте рассмотрим, что делает весь этот код.

Сначала мы устанавливаем наши clientID , clientSecret , authorizationURL , tokenURL и callbackURL из нашего объекта jawboneAuth мы определили в начале файла. Это делается с помощью new JawboneStrategy() .

Далее у нас есть функция обратного вызова, которая обрабатывает эти данные. Мы используем token и done значения в этой функции обратного вызова. token — это токен доступа Jawbone UP API, который мы должны включить в любые вызовы API, чтобы доказать, что мы аутентифицированы. done — это функция обратного вызова, которая возвращает наши данные в приложение.

Мы передаем токен доступа вместе с идентификатором клиента и секретом, определенными ранее, в модуль jawbone-up в объекте параметров:

 var options = { access_token: token, client_id: jawboneAuth.clientID, client_secret: jawboneAuth.clientSecret }, up = require('jawbone-up')(options); 

Модуль jawbone-up — это Node-модуль, который дает нам доступ к конечным точкам Jawbone UP API. Это вызовы, которые мы делаем API для возврата пользовательских данных (например, GET https://jawbone.com/nudge/api/v.1.1/users/@me/sleeps ), однако модуль jawbone-up позволяет нам получить доступ это в функциях, таких как up.moves.get() и up.sleeps.get() . В нашем примере мы будем использовать up.sleeps.get() для получения данных сна.

В up.sleeps.get() у нас есть две переменные, err и body . Если при получении данных от API возникает ошибка, она будет возвращена в переменной err поэтому мы проверяем это в начале нашего обратного вызова.

В противном случае мы получаем наши данные в виде строки JSON в переменной body . Переменная body будет содержать строку значений JSON, которая будет выглядеть так:

 { "meta": { "user_xid": "Hllksn238c-KJBu2esff_Q", "message": "OK", "code": 200, "time": 1428562859 }, "data": { "items": [ { "time_updated": 1428534140, "xid": "8060gi-3V-kLT-niK4ZxB2NLqnct9_2B", "title": "for 7h 45m", "time_created": 1428504300, "time_completed": 1428533100, "details": { "body": 0, "sound": 15000, "tz": "Australia/Sydney", "awakenings": 0, "light": 12900, "mind": 0, "asleep_time": 1428505800, "awake": 1500, "rem": 0, "duration": 28800, "smart_alarm_fire": 0, "quality": 84, "awake_time": 1428533100, "sunrise": 1428524040, "sunset": 1428565320 }, "date": 20150409, "shared": true, "sub_type": 0 }, { "time_updated": 1428447559, "xid": "8060gi-3V-nmNeDAWAAXjwzpZx2RQOgg", "title": "for 7h 38m", "time_created": 1428418945, "time_completed": 1428447488, "details": { "body": 0, "sound": 13985, "tz": "Australia/Sydney", "awakenings": 1, "light": 13501, "mind": 0, "asleep_time": 1428419639, "awake": 1057, "rem": 0, "duration": 28543, "smart_alarm_fire": 0, "quality": 78, "awake_time": 1428447300, "sunrise": 1428437580, "sunset": 1428478980 }, "date": 20150408, "shared": true, "sub_type": 0 } ], "links": { "next": "/nudge/api/v.1.1/users/Hllksn238c-KJBu2esff_Q/sleeps?page_token=1427987112334&limit=10" }, "size": 10 } } 

Все, что мы хотим, в data . Мы анализируем приведенные выше значения в объект JavaScript с помощью JSON.parse(body) и присваиваем значения в ключе data переменной с именем jawboneData :

 var jawboneData = JSON.parse(body).data; 

Затем у нас есть цикл for, который проходит через каждый элемент массива в data и форматирует наши дату и время ожидания перед возвратом их в наш шаблон для отображения.

 var date = jawboneData.items[i].date.toString(), year = date.slice(0,4), month = date.slice(4,6), day = date.slice(6,8); jawboneData.items[i].date = day + '/' + month + '/' + year; 

Здесь мы читаем дату, конвертируем ее в строку, а затем сами выделяем день, месяц и год. Он возвращается как значение 20150408 , поэтому мы выделяем первые четыре цифры как год, две после этого как месяц и последние две как день. Затем мы организуем его так, чтобы оно было DD/MM/YYYY Если вы предпочитаете форматировать его в формате даты США, вы можете переключить месяц и день:

 jawboneData.items[i].date = month + '/' + day + '/' + year; 

Jawbone API возвращает относительно хорошо отформатированное значение длительности сна в качестве title которое выглядит так: "for 9h 43m" . Мы можем использовать это, но удаляем часть "for " следующим образом:

 jawboneData.items[i].title = jawboneData.items[i].title.replace('for ', ''); 

Затем мы возвращаем эти данные в функцию обратного вызова нашего Passport, которая отобразит наш userdata.ejs . Для этого мы возвращаем нашу переменную jawboneData функцию. Также есть console.log чтобы мы могли видеть в журнале, когда данные Jawbone UP отправлены для отображения:

 return done(null, jawboneData, console.log('Jawbone UP data ready to be displayed.')); 

Использование HTTPS

Как я упоминал ранее, чтобы использовать Jawbone UP API, нам нужно запустить наш сервер с HTTPS, поскольку служба Jawbone требует, чтобы обе стороны работали с HTTPS. Если callbackURL не установлен на https вы получите сообщение об ошибке «Invalid redirect» при попытке войти в систему.

Чтобы наш пример работал, мы будем использовать самозаверяющий сертификат. Если вы делаете это на живом сайте, вам нужно будет получить надлежащие сертификаты от действующего центра сертификации.

В server.js мы определили две опции SSL:

 sslOptions = { key: fs.readFileSync('./server.key'), cert: fs.readFileSync('./server.crt') }; 

Это расположение файлов на нашем сервере наших двух файлов, связанных с аутентификацией:

  • ключ — это закрытый ключ для нашего сервера
  • cert — это наш собственный сертификат

Создать личный ключ для нашего сервера

Для генерации закрытого ключа нам нужно использовать OpenSSL Toolkit . Пользователи Mac OSX и Linux должны иметь эту предустановленную версию. Для пользователей Windows вы можете установить Cygwin , выполнить поиск «openssl» на экране «Выбор пакетов» и выбрать появившийся пакет.

Мы можем сгенерировать этот закрытый ключ, открыв наш терминал, перейдя в папку для нашего сервера и выполнив следующую команду:

 openssl genrsa -out server.key 2048 

Это создает частный ключ сервера, готовый к использованию, называемый server.key .

Генерация запроса на подпись сертификата (CSR)

Затем нам нужно сгенерировать CSR. Обычно это отправляется в центр сертификации, но в нашем случае мы будем подписывать его сами для целей тестирования.

Чтобы создать CSR, используя наш закрытый ключ, который мы создали выше, выполните следующую команду:

 openssl req -new -key server.key -out server.csr 

Вам будет дан список вопросов для ответа, ответьте на них, и вы получите CSR в виде файла с именем server.csr .

Создайте подписанный сертификат, используя закрытый ключ нашего сервера

Наконец, чтобы создать самозаверяющий сертификат без центра сертификации, мы запускаем следующую команду для создания сертификата, который будет действителен в течение одного года:

 openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 365 

Эта команда должна была сгенерировать файл server.crt — это ваш сертификат.

Удалить наш запрос сертификата

Для тех, кто хочет держать вещи в порядке и самостоятельно подписывает свой сертификат, мы можем удалить server.csr как наш сертификат теперь подписан.

Мы готовы к HTTPS

С нашим закрытым ключом и сертификатом, готовым и определенным в нашем файле Node, наш сервер готов к работе как HTTPS. Следующий код запускает сервер, используя HTTPS и наши sslOptions:

 var secureServer = https.createServer(sslOptions, app).listen(port, function(){ console.log('UP server listening on ' + port); }); 

Наши EJS файлы

Наш HTML- .ejs для этого приложения находится в файлах .ejs поэтому мы можем включать в них переменные JavaScript при необходимости. Все эти файлы находятся в /views . index.ejs очень прост и содержит только заголовок, инструкции и кнопку входа в систему, которые перейдут в /login/jawbone :

 <body> <h1>Jawbone UP Sleep Data</h1> <p>Log in to see your latest sleep data.</p> <a href="/login/jawbone" class="btn">Login</a> </body> 

userdata.ejs — это место действия. Главное, на чем мы можем сосредоточиться — это наш стол:

 <table class="sleep-table"> <thead> <tr> <th>Date</th> <th>Sleep time</th> </tr> </thead> <tbody> <% for (var i=0; i<items.length; i++) { %> <tr> <td><%= items[i].date %></td> <td><%= items[i].title %></td> </tr> <% } %> </tbody> </table> 

Для новичков в EJS мы встраиваем JavaScript в теги <% и %> .

Мы передаем items в шаблон пользовательских данных, который мы повторяем, используя цикл for, например: <% for (var i=0; i<items.length; i++) { %> .

Каждая дата и заголовок затем вставляются в наш HTML с помощью <%= items[i].date %> и <%= items[i].title %> .

Наше приложение в действии

Чтобы запустить приложение, зайдите в свой терминал и запустите:

 node server.js 

После запуска перейдите по http://localhost:5000 и вы увидите нашу начальную страницу:

Наша начальная страница

Если мы нажмем кнопку входа, мы перейдем по http://localhost:5000/login/jawbone , который направит нас на страницу аутентификации Jawbone UP. Страница запросит у нас данные для входа в Jawbone. После того, как вы введете эти данные или если вы уже вошли на сайт Jawbone, вы будете перенаправлены на страницу авторизации, запрашивающую доступ к вашим данным пользователя. Нажмите «Согласен»:

Данные для входа найдены

Когда мы нажимаем согласиться, мы должны быть http://localhost:5000/sleepdata страницу http://localhost:5000/sleepdata с таблицей возвращенных данных сна:

Наша страница данных сна

И если мы нажмем кнопку «Выйти», она должна выйти из системы и перенаправить нас обратно на домашнюю страницу.

Вывод

На этом мы завершаем наш обзор основ подключения к Jawbone UP API и возврата данных на сервер Node.

Следующие шаги могут включать настройку базы данных для хранения данных для будущего использования, создание учетных записей пользователей для вашего приложения, увеличение объема данных, которые вы извлекаете из API UP, изменение их отображения (возможно, добавление некоторых симпатичных графиков! ) и более. Объедините эти данные с любым количеством других API, и потенциал для действительно полезных приложений огромен!

Другие полезные ресурсы