Code Monkey home page Code Monkey logo

mif's Introduction

Go Report Card Build Status Contributions Welcome

Важно! Этот проект находится в архивном состоянии и не следует некоторым лучшим практикам, которые имеет смысл рассматривать при разаботке сервисов на Go. Если вы хотите узнать побольше о лучших практиках написания сервисов на Go, пожалуйста, ознакомьтесь с докладом Best Practices for Cloud Native Go Services или другими подходящими источниками.


Этот репозиторий представляет собой реализацию неофициального REST API для книг издательства «МИФ».

Всё написано на Go.

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

Вклад в проект посредством создания issues и pull requests приветствуется 🤓

Документация:

БД

Используется БД PostgreSQL.

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

Структура данных

Можно воспользоваться готовым дампом из db или задать структуру базы данных, используя нижеследующее описание. В случае развертывания сервиса из Docker-образов (см. инструкцию ниже), дамп базы накатывается автоматически.

База данных

CREATE DATABASE mifbooks WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'en_US.utf8' LC_CTYPE = 'en_US.utf8';

Необходимые таблицы

CREATE TABLE IF NOT EXISTS categories (
  id SERIAL PRIMARY KEY,
  title VARCHAR(256) NOT NULL,
  created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL
);

CREATE TABLE IF NOT EXISTS books (
  id SERIAL PRIMARY KEY,
  mif_id INTEGER,
  category_id INTEGER,
  title VARCHAR(512),
  isbn VARCHAR(64),
  authors VARCHAR(512),
  url VARCHAR(512) UNIQUE NOT NULL,
  created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  is_visible BOOLEAN DEFAULT NULL
);

CREATE TABLE IF NOT EXISTS books_broken (
  id SERIAL PRIMARY KEY,
  url VARCHAR(512) UNIQUE NOT NULL,
  created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL
);

CREATE TYPE volume_type AS ENUM ('paperbook', 'ebook', 'audiobook');
CREATE TABLE IF NOT EXISTS volumes (
  id SERIAL PRIMARY KEY,
  book_id INTEGER NOT NULL REFERENCES books(id),
  type volume_type NOT NULL,
  created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  
  UNIQUE (book_id, type)
);

 CREATE TABLE IF NOT EXISTS users (
  id SERIAL PRIMARY KEY,
  email VARCHAR(128) UNIQUE NOT NULL,
  token VARCHAR(128) UNIQUE NOT NULL,
  created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
  updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL
 );
 
 CREATE TABLE IF NOT EXISTS library (
   id SERIAL PRIMARY KEY,
   user_id INTEGER NOT NULL REFERENCES users(id),
   volume_id INTEGER NOT NULL REFERENCES volumes(id),
   created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
   updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
   
   UNIQUE (user_id, volume_id)
 );

Импорт данных

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

Подробности - в data

Запуск сервера

Пример запуска с помощью Docker'а

Самый простой способ поднять сервер с API. В этом случае из DockerHub'а будут подтянуты уже существующие образы с БД и приложением.

docker-compose up

Запуск сервера занимает ~10-15 секунд (время раската дампа БД). После этого сразу можно делать запросы к API. По умолчанию сервер слушает порт 80. Для проверки работоспособности можно попробовать запрос http://127.0.0.1/api/v1/books. Альтернативную конфигурацию можно задать в файле docker-compose.yml.

Для сборки и отправки образов используется скрипт make.sh, при желании его можно кастомизировать в своих целях.

Пример "сырого" запуска сервера API

В этом случае будет произведен запуск приложения с использованием go run (полезно для отладки).

env HOST=127.0.0.1 PORT=80 \
DB_HOST=localhost DB_PORT=5432 DB_USER=postgres DB_PASS=mysecretpassword DB=mifbooks \
go run mif.go --debug

Параметры host и port отвечают за то, по какому адресу и порту слушать запросы. Параметры с префиксом db_ задают конфигурацию доступа к БД PostgreSQL: хост, порт, пользователь, пароль, название БД.

Документация по методам

Все книги издательства

Список книг

GET /api/v1/books - получить список книг издательства. В выдаче книги будут отсортированы по id в обратном порядке: от более новых к более старым.

Опциональные параметры запроса:

  • search - поиск книги по части названия

  • author - поиск книги по автору

  • mif_id - поиск книги по идентификатору в МИФ

  • type - тип "носителя" книги: paperbook, ebook, audiobook

  • limit - "пагинация": кол-во записей на странице (по умолчанию 10)

  • offset - "пагинация": сдвиг записей (по умолчанию 0)

Пример запроса:

curl -X GET http://mif.grahovac.me/api/v1/books?search=маркетинг&limit=50

Информация о книге

GET /api/v1/books/:id - получить конкретную книгу по ее идентификатору в БД

Пример запроса:

curl -X GET http://mif.grahovac.me/api/v1/books/33

Личная библиотека

Запросы к личной библиотеке подразумевают аутентификацию пользователя. Для аутентификации используется секретный токен, передаваемый через параметр запроса token.

В случае, если запрос предполагает наличие тела запроса, оно передается в формате JSON.

Список книг

GET /api/v1/library - получить список книг, имеющихся в собственной библиотеке. В выдаче книги будут отсортированы по id в обратном порядке: добавленные последними будут в начале выдачи.

Обязательные параметры запроса:

  • token - уникальный токен пользователя для аутентификации

Опциональные параметры запроса:

  • limit - "пагинация": кол-во записей на странице (по умолчанию 10)
  • offset - "пагинация": сдвиг записей (по умолчанию 0)

Пример запроса:

curl -X GET http://mif.grahovac.me/api/v1/library?token=6f9c1a78-36c7-4703-adb7-e0101e480c64&limit=50

Добавить книгу в свою библиотеку

POST /api/v1/library

Обязательные параметры запроса:

  • token - уникальный токен пользователя для аутентификации

Обязательные параметры тела запроса:

  • book_id - идентификатор добавляемой книги
  • type - "носитель" добавляемой книги: paperbook, ebook, audiobook

Пример запроса:

curl -X POST http://mif.grahovac.me/api/v1/library?token=6f9c1a78-36c7-4703-adb7-e0101e480c64 \
-H 'Content-Type: application/json' \
-d '{"book_id": 33, "type": "paperbook"}'

Удалить книгу из своей библиотеки

DELETE /api/v1/library

Обязательные параметры запроса:

  • token - уникальный токен пользователя для аутентификации

Обязательные параметры тела запроса:

  • book_id - идентификатор добавляемой книги
  • type - "носитель" добавляемой книги: paperbook, ebook, audiobook.

Пример запроса:

curl -X DELETE http://mif.grahovac.me/api/v1/library?token=6f9c1a78-36c7-4703-adb7-e0101e480c64 \
-H 'Content-Type: application/json' \
-d '{"book_id": 33, "type": "paperbook"}'

Road map

  • Тесты!
  • Добавить клиента для API и консольное приложение для работы с ним
  • Добавить swagger-документацию для API
  • Рефакторинг кишков middleware (запросы к БД)
  • Актуализировать Makefile набором полезных команд
  • Поддержка HTTPS
  • Запуск импорта данных по расписанию
  • Утилита для управления пользователями

mif's People

Contributors

aleksi avatar casper1149 avatar rumyantseva avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mif's Issues

Ошибка на запрос api/v1/books?search=&author=Катерина Евгения

В базе данных есть книга:

"title": "Ежедневник SelfMama",
"authors": "Оксана Татарина, Полина Рычалова, Катерина Назарова, Евгения Которова",

Если ищу по параметру "author": Катерина Евгения ничего не найдено.

{
	"data": null,
	"meta": {
		"total": 0,
		"limit": 10,
		"offset": 0
	}
}

В логах вижу:

app_1  | 2017/03/12 13:41:37 >>> SELECT "books"."id", "books"."mif_id", "books"."category_id", "books"."title", "books"."isbn", "books"."authors", "books"."url", "books"."created_at", "books"."updated_at", "books"."is_visible" FROM "books"  WHERE is_visible = true AND books.authors ILIKE $1 ORDER BY books.id DESC LIMIT 10 OFFSET 0 [`%Катерина Евгения%`]
app_1  | 2017/03/12 13:41:37 <<< SELECT "books"."id", "books"."mif_id", "books"."category_id", "books"."title", "books"."isbn", "books"."authors", "books"."url", "books"."created_at", "books"."updated_at", "books"."is_visible" FROM "books"  WHERE is_visible = true AND books.authors ILIKE $1 ORDER BY books.id DESC LIMIT 10 OFFSET 0 [`%Катерина Евгения%`] 5.987687ms
app_1  | 2017/03/12 13:41:37 >>> SELECT COUNT(books.*) FROM books WHERE is_visible = true AND books.authors ILIKE $1 [`%Катерина Евгения%`]
app_1  | 2017/03/12 13:41:37 <<< SELECT COUNT(books.*) FROM books WHERE is_visible = true AND books.authors ILIKE $1 [`%Катерина Евгения%`] 3.769873ms

Ошибка на запрос "http://127.0.0.1/api/v1/books?search=Маминой помощнице"

Делаю запрос вида http://127.0.0.1/api/v1/books?search=Маминой помощнице получаю ошибку: Эта книга "Маминой помощнице" есть в базе. Если набираю несколько пробелов между словами, эта книга не видна. Несколько пробела между словами должны игнорироваться.


{
	"data": null,
	"meta": {
		"total": 0,
		"limit": 10,
		"offset": 0
	}
}

В логах вижу:

app_1  | 2017/03/12 12:39:46 >>> SELECT "books"."id", "books"."mif_id", "books"."category_id", "books"."title", "books"."isbn", "books"."authors", "books"."url", "books"."created_at", "books"."updated_at", "books"."is_visible" FROM "books"  WHERE is_visible = true AND books.title ILIKE $1 ORDER BY books.id DESC LIMIT 10 OFFSET 0 [`%Маминой      помощнице%`]
app_1  | 2017/03/12 12:39:46 <<< SELECT "books"."id", "books"."mif_id", "books"."category_id", "books"."title", "books"."isbn", "books"."authors", "books"."url", "books"."created_at", "books"."updated_at", "books"."is_visible" FROM "books"  WHERE is_visible = true AND books.title ILIKE $1 ORDER BY books.id DESC LIMIT 10 OFFSET 0 [`%Маминой      помощнице%`] 19.491449ms
app_1  | 2017/03/12 12:39:46 >>> SELECT COUNT(books.*) FROM books WHERE is_visible = true AND books.title ILIKE $1 [`%Маминой      помощнице%`]
app_1  | 2017/03/12 12:39:46 <<< SELECT COUNT(books.*) FROM books WHERE is_visible = true AND books.title ILIKE $1 [`%Маминой      помощнице%`] 4.752472ms

Организация кода

Привет.
Могли бы вы рассказать об организации исходников в проекта?
Я наблюдаю у вас точку входна, которая является частью исходников, mif.go, там же где лежат vendor, .gitignore и прочий шум, который рядом с исходниками, как я считаю, быть не должен.
Могли бы вы посоветовать, как жить?
Я чего-то не понимаю в go-way или при создании этого проекта не было такой задачи?
Спасибо за внимание, всего доброго!

Ошибка на запрос /api/v1/books?search=маркетинг&type=ebook

Делаю запрос вида http://127.0.0.1/api/v1/books?search=маркетинг&type=ebook получаю ошибку:

{
	"error": {
		"code": 500,
		"message": "Something went wrong. We will repair it as soon as possible."
	}
}

В логах вижу:

db_1   | ERROR:  syntax error at or near "v" at character 46
db_1   | STATEMENT:  SELECT COUNT(books.*) FROM booksJOIN volumes v ON v.book_id = books.id  WHERE is_visible = true AND books.title ILIKE $1 AND v.type = $2
app_1  | 2017/03/12 11:36:40 >>> SELECT COUNT(books.*) FROM booksJOIN volumes v ON v.book_id = books.id  WHERE is_visible = true AND books.title ILIKE $1 AND v.type = $2 [`%маркетинг%`, `ebook`]
app_1  | 2017/03/12 11:36:40 <<< SELECT COUNT(books.*) FROM booksJOIN volumes v ON v.book_id = books.id  WHERE is_visible = true AND books.title ILIKE $1 AND v.type = $2 [`%маркетинг%`, `ebook`] 733.283µs
app_1  | time="2017-03-12T11:36:40Z" level=error msg="Couldn't get data from DB for books total count: pq: syntax error at or near \"v\""

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.