Учебное пособие по настройке Firestore в качестве базы данных - очень удобное решение ваших проблем с хранилищем!
Мне нужно было создать хранилище для некоторых данных для моегочленство в клубе, место, где я преподаю программирование.
Я хотел, чтобы мои пользователи могли вручную сказать «Я прошел этот курс», нажав кнопку.
По сути, я хотел сохранить определенный объект для каждого пользователя.
Настройка Firebase
Я решил использоватьFirebaseдля этого, и в частностиБаза данных Firestoreони предоставляют.
Уровень бесплатного пользования для него велик: до 1 ГБ хранимых данных и 10 ГБ передачи по сети в месяц. Сильно превышаю мои оценки того, что мне нужно!
Откройте веб-сайт Firebase по адресуhttps://firebase.google.com/
Firebase - это продукт Google, поэтому после входа в Google вы, по сути, также входите в Firebase.
Я создал новый проект Firebase, нажав «Создать проект».
Я дал ему имя:
Вот и все:
Я щелкнул значок «Интернет» рядом с iOS и Android и ввел название приложения:
И Firebase сразу же предоставила мне необходимые ключи доступа вместе с некоторыми примерами кода:
Сразу после этого Firebase предложила мне добавить некоторые правила безопасности для базы данных.
По умолчанию вы можете выбрать 2 вещи: открытые для всех или закрытые для всех. Я начал открываться для всех, что они называюттестовый режим.
Вот и все! Я был готов к работе, создав коллекцию.
Что за коллекция? В терминологии Firestore мы можем создавать множество разных коллекций и назначать документы каждой коллекции.
Тогда документ может содержать поля и другие коллекции.
Это не сильно отличается от других баз данных NoSQL, напримерMongoDB.
Очень рекомендую посмотретьплейлист YouTube по этой теме, это очень хорошо сделано.
Итак, я добавил свою коллекцию, которую назвалusers
.
Я хотел идентифицировать каждого пользователя с помощью специальной строки, которую я называюid
.
Код внешнего интерфейса
Теперь мы переходим к части JavaScript.
В нижний колонтитул я включил эти 2 файла, предоставленные Firebase:
<script src="https://www.gstatic.com/
firebasejs/7.2.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/
firebasejs/7.2.1/firebase-firestore.js"></script>
затем я добавилПрослушиватель событий DOMContentLoaded, чтобы убедиться, что я запустил код, когда DOM будет готов:
<script>
document.addEventListener('DOMContentLoaded', event => {
})
</script>
Там я добавил конфигурацию Firebase:
const firebaseConfig = {
apiKey: "MY-API-KEY",
authDomain: "MY-AUTH-DOMAIN",
projectId: "MY-PROJECT-ID"
}
Я передал этот объектfirebase.initializeApp()
, а затем я позвонилfirebase.firestore()
чтобы получить ссылку на объект базы данных:
firebase.initializeApp(firebaseConfig)
const db = firebase.firestore()
Теперь я создал сценарий для заполнения идентификаторов пользователей из списка, который был у меня в моем бэкэнде, используя простой цикл:
const list = [/*...my list...*/]
list.forEach(item => {
db.collection(‘users’).doc(item).set({})
})
..и я запустил его один раз, чтобы заполнить базу данных. Я в основном программносоздал документ для каждого пользователя.
Это очень важно, потому что, как только я создал документ, это означало, что я могу ограничить разрешения только на обновление этих документов и запретить добавление новых или удаление их (что мы сделаем позже)
Хорошо, теперь у меня была сложная логика для идентификации идентификатора пользователя и идентификатора курса, о которой я не буду вдаваться, потому что это не связано с нашей задачей здесь.
Как только я это собрал, я мог получить ссылку на объект:
const id = /* the user ID */
const course = /* the course ID */
const docRef = db.doc(`membership/${id}`)
Большой! Теперь я могу получить ссылку на документ из Firebase:
docRef.get().then(function(doc) {
if (doc.exists) {
const data = doc.data()
document.querySelector('button')
.addEventListener('click', () => {
data[course] = true
docRef.update(data)
})
} else {
//user does not exist..
}
})
Моя логика на самом деле была намного сложнее, потому что у меня есть другие движущиеся части, но вы поняли!
Я инициализирую данные документа, вызываяdoc.data()
и когда нажимается кнопка (я предполагаю, что это кнопка с надписью «Я прошел курс»), мы связалиtrue
логическое значение идентификатора клуба.
Позже, при последующих загрузках страницы со списком курсов, я могу инициализировать страницу и назначить класс, если курс был завершен, например:
for (const [key, value] of Object.entries(data[course])) {
const element = document.querySelector('.course-' + course)
if (element) {
element.classList.add('completed')
}
}
Проблема с разрешениями
Я запустил Firebase в тестовом режиме, помните? Это делает базу данных открытой для всех - всех, у кого есть ключи доступа, которые являются общедоступными и публикуются в коде, отправленном во внешний интерфейс.
Поэтому мне нужно было сделать одно: определить разрешенный уровень разрешений.
И я наткнулся на довольно важную проблему.
Используя консоль Firebase в разделеПравила, мы можем урезать разрешение. Изначально это было правилом по умолчанию:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
Я изменил правила наread, update
, поэтому можно только обновлять документ, но не создавать новые:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, update;
}
}
}
Но я не смог помешать людям использовать Firebase API, теперь свободно доступный в браузере, для игры и перечисления всех других документов в коллекции, получая доступ к файлам других людей.
Хотя при этом не обрабатывались конфиденциальные данные, отправить этот код было невозможно.
Перенос кода из внешнего интерфейса в серверную часть через настраиваемый API
Проблема с разрешением была преградой на пути.
Я думал об удалении всего кода, который у меня был, но в конце концов понял, что могу полностью скрыть весь доступ к API из браузера и использовать службу Node.js для запуска Firebase API.
Это также распространенный метод скрытия закрытых / секретных ключей, требуемых службами: спрячьте их за сервером, которым вы управляете.
Вместо вызова Firebase из браузера я создал набор конечных точек на своем собственном сервере, например:
- Опубликовать в
/course
установить курс как пройденный - Опубликовать в
/data
чтобы получить данные, связанные с пользователем
и я получаю к ним доступ, используяПолучить API:
const options = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ id, course, lesson })
}
const url = BASE_URL + '/lesson'
fetch(url, options).catch(err => {
console.error('Request failed', err)
})
Вся логика с нажатиями кнопок и т. Д. Остается в коде на стороне клиента, конечно, я просто убрал логику Firebase.
На стороне сервера Node.js я установил официальнуюfirebase
пакет с использованиемnpm install firebase
и потребовал это:
const firebase = require('firebase')
Я создалвыражатьсервер для использованияCORSи я инициализировал Firebase:
const firebaseConfig = {
apiKey: process.env.APIKEY,
authDomain: process.env.AUTHDOMAIN,
projectId: process.env.PROJECTID
}
firebase.initializeApp(firebaseConfig)
const db = firebase.firestore()
Тогда код точно такой же, как тот, который я использовал во внешнем интерфейсе, за исключением того, что теперь он запускается при вызовах конечных точек HTTP. Это код, который возвращает конкретный документ из нашей коллекции.
const getData = async (id) => {
const doc = await db.doc(`membership/${id}`).get()
const data = doc.data()
if (!data) {
console.error('member does not exist')
return
}
return data
}
app.post(’/data’, cors(), async (req, res) => {
const id = req.body.id
if (id) {
res.json(await getData(id))
return
}
res.end()
})
и вот API, чтобы установить курс как завершенный:
const setCourseAsCompleted = async (id, course) => {
const doc = await db.doc(`membership/${id}`).get()
const data = doc.data()
if (!data) {
console.error('member does not exist')
return
}
if (!data[course]) {
data[course] = {}
}
data[course]['done'] = true
db.doc(`membership/${id}`).update(data)
}
app.post(’/course’, cors(), (req, res) => {
const id = req.body.id
const course = req.body.course
if (id && course) {
setCourseAsCompleted(id, course)
res.end(‘ok’)
return
}
res.end()
})
В основном это все. Требуется еще немного кода для обработки другой логики, но суть Firebase такова, что я опубликовал. Теперь я также могу добавить пользователя для своей серверной службы и ограничить весь другой доступ к API Firebase и усилить его безопасность.
Дополнительные руководства по услугам:
- Как начать с хостинга Firebase
- Учебник по размещению вашего статического сайта на Netlify
- Линтеры и средства форматирования кода для веб-разработчиков
- Автоматический запуск запускается на Netlify
- Glitch, отличная платформа для разработчиков
- Airtable API для разработчиков
- Как пройти аутентификацию в любом Google API
- Zeit Now Учебное пособие
- Учебное пособие по лямбда-функциям Netlify
- Как использовать Firebase Firestore в качестве базы данных
- Как я исправил завершающую косую черту в переписчиках Netlify
- Как получить доступ к параметрам запроса в функциях Netlify
- Как использовать переменные среды в функциях Netlify
- Как использовать пакеты npm в функциях Netlify
- Как создать свой первый VPS на DigitalOcean