DevGang
Авторизоваться

Настоящую любовь нетрудно найти с RedisJSON

В первом выпуске этой серии мы рассмотрели важность JSON,  баз данных JSON и RedisJSON, установили Redis Cloud, Redis Stack, and Redis Insight, а также то, как мы можем хранить все типы данных (скалярные, объективные, массив объектов) в RedisJSON. Мы приближались с каждым шагом к нашей цели - найти идеальные пары для вернувшихся на свободу заключенных. В конце концов, каждый может найти настоящую любовь. Давайте сделаем еще один шаг к нашей цели в этой статье.

Время для творчества

Как мы можем подготовить наши измерения данных для наших совпадений с помощью кода? С помощью Golang мы изучили, как беспрепятственно взаимодействовать с нашей базой данных RedisJSON и позволить освободившимся заключенным без труда указать свои интересы. 

Все это описано в первом нашем уроке. Изучить его вы можете пройдя по ссылке ниже,

Итак, наше руководство по созданию инструмента знакомств (2 части)::

  1. Инструмент знакомств для освободившихся заключенных
  2. Настоящую любовь нетрудно найти с RedisJSON

Творим, создаем, претворяем в жизнь

Мы будем использовать простую структуру каталогов и шаблон расположения кода (насколько это возможно). В более серьезной реализации рекомендуется использовать больше идиоматических архитектурных стилей Golang. Однако мы хотели бы разделить проблемы в самых простых формах.Также мы будем использовать стандарт REST API. Этот код будет построен как монолит, чтобы избежать сложностей, но позже его можно будет масштабировать до гораздо более сложных архитектур. К микроуслугам и лучшим практикам  Lords:

Давайте создадим каталог для нашего кода. В UNIX-подобных системах мы можем сделать: 

mkdir dating-app && cd dating-app

Было бы здорово начать с настройки и приведения в порядок некоторых наших зависимостей. Запустите это в корневом проекте вашего терминала: 

#go mod init {your-repo-name}
#For me I have:
go mod init github.com/femolacaster/dating-app

#Tidy things up
go mod tidy

#Call on your Redis Soldiers
go get github.com/gomodule/redigo/redis
go get github.com/nitishm/go-rejson/v4

#Let us include MUX for our API routing
go get -u github.com/gorilla/mux

Последующим шагом будет создание следующих маршрутов в папке с именем routes в корневом каталоге нашего приложения:

[route-dir]/routes/routes.go

package routes

import (
    "github.com/femolacaster/dating-app/controllers"
    "github.com/gorilla/mux"
)

func Init() *mux.Router {
    route := mux.NewRouter()

    route.HandleFunc("/api/v1/criteria", controllers.ShowAll)
    route.HandleFunc("/api/v1/criteria", controllers.Add).Methods("POST")
    route.HandleFunc("/api/v1/criteria/ {id}/dimension", controllers.ShowDimension)
    return route
}

В приведенном выше коде показана простая маршрутизация. Функция Init возвращает 3 экспортированных маршрута, которые позволяют добавить новые критерии для бывших заключенных, которые используют метод POST, отображают все различные критерии знакомства заключенных в приложении и возвращают размерность определенных критериев (случайных (Casual) или серьезных (Serious)), используя метод GET.

Хорошим следующим шагом было бы создание помощников для нашего кода. Помощники - это функции, которые вы постоянно используете в своем коде. Две вспомогательные функции, идентифицированные в этом случае, - «RenderErrorResponse» и «RenderResponse» соответственно. Эти функции помогают отображать вывод данных нашего API в простом формате в зависимости от того, является это ошибкой или нет. 

Что мы имеем в:

[route-dir]/helpers/dating.go

package helpers

import (
    "encoding/json"
    "net/http"
)

type ErrorResponse struct {
    Error string `json:"error"`
}

func RenderErrorResponse(w http.ResponseWriter, msg string, status int) {
    RenderResponse(w, ErrorResponse{Error: msg}, status)
}

func RenderResponse(w http.ResponseWriter, res interface{}, status int) {
    w.Header().Set("Content-Type", "application/json")
    content, err := json.Marshal(res)
    if err != nil {
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
    w.WriteHeader(status)
    if _, err = w.Write(content); err != nil {
    }
}

Мы можем добавить еще одну вспомогательную функцию. Все что он делает - это подключается к нашей локальной базе данных RedisJSON и выводит экземпляр подключения клиента Redigo, который мы можем использовать для нашей логики: 

func NewRedisConn() *rejson.Handler {
    var addr = flag.String("Server", "localhost:6379", "Redis server address")
    rh := rejson.NewReJSONHandler()
    flag.Parse()
    // Redigo Client
    conn, err := redis.Dial("tcp", *addr)
    if err != nil {
        log.Fatalf("Failed to connect to redis-server @ %s", *addr)
    }
    defer func() {
        _, err = conn.Do("FLUSHALL")
        err = conn.Close()
        if err != nil {
            log.Fatalf("Failed to communicate to redis-server @ %v", err)
        }
    }()
    rh.SetRedigoClient(conn)
    return rh
}

Давайте создадим логику для наших маршрутов.

Мы создаем новый файл: 

[route-dir]/controllers/dating.go

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

Первое, что нужно сделать в этом разделе, - сохранить различные интересы в структуре, а затем внедрить интересы и другие детали для формирования критериев заключенного, как показано в этой структуре:

type Criteria struct {
    ID                int             `json:"id"`
    Name              string          `json:"name"`
    Height            float32         `json:"height"` //height in feet and inches
    WeightKG          int             `json:"weight"`
    SexualOrientation string          `json:"sexualOrientation"`
    Age               int             `json:"age"`
    CasualInterest    CasualInterest  `json:"casualInterest"`
    SeriousInterest   SeriousInterest `json:"seriousInterest"`
}
type SeriousInterest struct {
    Career        bool `json:"career"`
    Children      bool `json:"children "`
    Communication bool `json:"communication"`
    Humanity      bool `json:"humanity"`
    Investment    bool `json:"investment"`
    Marriage      bool `json:"marriage"`
    Religion      bool `json:"religion"`
    Politics      bool `json:"politics"`
}
type CasualInterest struct {
    Entertainment bool `json:"entertainment"`
    Gym           bool `json:"gym"`
    Jewellries    bool `json:"jewellries"`
    OneNight      bool `json:"oneNight"`
    Restaurant    bool `json:"restaurant"`
    Swimming      bool `json:"swimming"`
    Travel        bool `json:"travel"`
    Yolo          bool `json:"yolo"`
}

Во всех наших логических функциях мы использовали возвращаемый экземпляр rejson Golang в функции helpers. Функция NewRedisConn будет использоваться для связи с нашей базой данных RedisJSON. 

rh := helpers.NewRedisConn()

Rejson - это модуль Redis, который реализует ECMA-404, стандарт обмена данными JSON в качестве собственного типа данных и позволяет хранить, обновлять и извлекать значения JSON из ключей Redis, который также поддерживает два популярных клиента Golang: Redigo и go-redis.

Вот в чем разница между Redigo и go-redis, чтобы сделать свой собственный осознанный выбор:

Redigo go-redis
Это менее безопасно для типов Это более безопасно для типов
Это может быть быстрее и проще в использовании Это может быть медленнее и может быть не проще в использовании, чем Redigo
Не используйте его, если планируете масштабировать базу данных до высокодоступного кластера Идеально подходит для кластеризации 

Выбор остается за вами. В этой статье мы выбрали более простой вариант  - Redigo, и вы увидите его использование в функциях controller.

Для нашей первой функции, которая добавляет критерии для заключенного:

func Add(w http.ResponseWriter, r *http.Request) {
    var req Criteria
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        helpers.RenderErrorResponse(w, "invalid request", http.StatusBadRequest)
        return
    }
    defer r.Body.Close()

    rh := helpers.NewRedisConn()

    res, err := rh.JSONSet("criteria", ".", &req)
    if err != nil {
        log.Fatalf("Failed to JSONSet")
        return
    }
    if res.(string) == "OK" {
        fmt.Printf("Success: %s\n", res)
        helpers.RenderResponse(w, helpers.ErrorResponse{Error: "Successfully inserted new Criteria to Database"}, http.StatusCreated)
    } else {
        fmt.Println("Failed to Set: ")
        helpers.RenderErrorResponse(w, "invalid request", http.StatusBadRequest)
    }
}

Вторая конечная точка, которая показывает все критерии, показана ниже: 

func ShowAll(w http.ResponseWriter, r *http.Request) {
    rh := helpers.NewRedisConn()
    criteriaJSON, err := redis.Bytes(rh.JSONGet("criteria", "."))
    if err != nil {
        log.Fatalf(("Failed to get JSON"))
        return
    }

    readCriteria := Criteria{}
    err = json.Unmarshal(criteriaJSON, &readCriteria)
    if err != nil {
        fmt.Printf("JSON Unmarshal Failed")
        helpers.RenderErrorResponse(w, "invalid request", http.StatusBadRequest)
    }
    fmt.Printf("Student read from RedisJSON:%#v\n", readCriteria)
    helpers.RenderResponse(w, helpers.ErrorResponse{Error: "Successful retrieval of criterias"}, http.StatusOK)

}

Так же вы самостоятельно можете узнать являются ли критерии для заключенного Casual или Serious.

Совет

Получите все критерии от RedisJSON, точно также как показано в функции ShowAll, но на этот раз с использованием ключа, который является идентификатором для получения этих критериев. Затем, поскольку структуры CasualInterest и SeriousInterest имеют логические поля bool, сравните два отдельных значения структуры, чтобы определить какое из них имеет наибольшее значение «1» или «true». Таким образом, вы можете определить заключенного, который склонен искать что-то серьезное или случайное.

В нашем корневом каталоге main.go мы можем создать наш сервер:

package main

import (
    "errors"
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    "github.com/femolacaster/dating-app/routes"
    "github.com/ichtrojan/thoth"
    "github.com/joho/godotenv"
)


func main() {

    logger, thothErr := thoth.Init("log")
    if thothErr != nil {
        log.Fatal(thothErr)
    }

    //warning, error, log, trace, metrics
    if envLoadErr := godotenv.Load(); envLoadErr != nil {
        logger.Log(errors.New("There was a problem loading an environmental file. Please check file is present."))
        log.Fatal("Error:::There was a problem loading an environmental file. Please check file is present.")
    }

    appPort, appPortExist := os.LookupEnv("APPPORT")

    if !appPortExist {
        logger.Log(errors.New("There was no Port variable for the application in the env file"))
        log.Fatal("Error:::There was no Port variable for the application in the env file")
    }
    address := ":" + appPort

    srv := &http.Server{
        Handler:           routes.Init(),
        Addr:              address,
        ReadTimeout:       1 * time.Second,
        ReadHeaderTimeout: 1 * time.Second,
        WriteTimeout:      1 * time.Second,
        IdleTimeout:       1 * time.Second,
    }

    log.Println("Starting server", address)
    fmt.Println("Go to localhost:" + appPort + " to view application")

    log.Fatal(srv.ListenAndServe())

}

Итак, запускаем наш сервер: 

В корне вашего проекта запустите код выполнив эту команду:

go run main.go

Мы успешно настроили простой API для освобожденных заключенных, чтобы получить их совпадения. 

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

Давайте углубимся в это утверждение. Убедитесь, что у вас включен экземпляр базы данных Redis и запустите RedisInsight, чтобы иметь представление о том, что происходит.

  • Рассмотрим простой вариант использования: MR Peter, который когда-то был заключенным, хочет заявить о своем удивительном профиле, демонстрирующем множество качеств, и надеется, что кто-то примет и полюбит его таким, какой он есть.  С помощью нашего API MR Peter может выполнять эту задачу с помощью мобильного клиента, IoT устройства, своего браузера и т.д. Возможно, говоря, набирая текст и т.д., что переводится следующим образом:
curl -X POST localhost :9000 /api/v1/criteria
   -H "Content-Type: application/json"
   -d ' {
    "id":DATIN00025,
    "name":"Mr Peter Griffin",
    "height":6.4,
    "weight":120,
    "sexualOrientation":"straight",
    "age":45,
    "casualInterest":{
       "entertainment":true,
       "gym":false,
       "jewellries":false,
       "oneNight":false,
       "restaurant":true,
       "swimming":false,
       "travel":false,
       "yolo":true
    },
    "seriousInterest":{
       "career":false,
       "children ":true,
       "communication":false,
       "humanity":false,
       "investment":false,
       "marriage":false,
       "religion":false,
       "politics":true
    }
 }
‘
  • Другой вариант использования: Mrs. Lois. Mrs. Lois желает связаться с кем-то кто сможет ее понять, кто сможет понять, что такое быть за решеткой, поскольку она тоже была в такой ситуации. Ей нужен этот мужчина, излучающий мужественность и энергию. Вызов нашего API через ее клиент, как показано ниже, творит волшебство, показывая ей всех мужчин, доступных для ее выбора: 
curl localhost :9000 /api/v1/criteria
   -H "Accept: application/json"
  • И еще один вариант: Miss Meg, желающая видеть обе стороны медали на непринужденном уровне. Никаких серьезных обязательств она не хочет. Вероятно, она хочет знать соответствует ли конкретная сладкая партия этой потребности. Она видит профиль Peter Griffin ранее и хочет определить есть ли у него какие-то случайные или серьезные намерения.  Miss Meg нажимает кнопку на своем мобильном телефоне, и все, что нужно сделать с ее мобильного телефона - это позвониь в нашу нереализованную конечную точку showDimension для Peter Griffin, чтобы узнать является ли он случайным кандидатом в аналогичном вызове, таким как: 
curl localhost :9000 /api/v1/criteria/ DATIN00025/dimension
   -H "Accept: application/json"

Итак,  в случаях с этими вариантами, Mr.Peter, Mrs. Lois и Miss. Meg мы разобрались. Мы смогли с легкостью найти идеальные пары.

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

Полным руководством вы можете ознакомиться пройдя по ссылке ниже:

  1. Инструмент знакомств для освободившихся заключенных
  2. Настоящую любовь нетрудно найти с RedisJSON
#Golang #Redis
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу