Computer >> 컴퓨터 >  >> 프로그램 작성 >> Redis

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

이 게시물에서는 데이터 저장을 위해 Flutter, Serverless Framework, Upstash 및 Redis를 사용하여 서버리스 모바일 애플리케이션을 구축할 것입니다.

Upstash란 무엇입니까?

Upstash는 Redis용 서버리스 데이터베이스입니다. Upstash를 사용하면 요청당 비용을 지불합니다. 즉, 데이터베이스를 사용하지 않을 때는 요금이 부과되지 않습니다.

Upstash는 데이터베이스를 구성하고 관리합니다. DynamoDB 및 Fauna와 같은 다른 데이터베이스에 대한 강력한 대안이며 다음과 같은 이점이 있습니다.

  • 낮은 지연 시간
  • REDIS API와 같은 사용 용이성

다음은 Upstash를 대체 클라우드 기반 솔루션과 비교한 자세한 문서로, 다음 프로젝트에서 Upstash를 선택해야 하는 이유를 명확히 보여줍니다.

사용 가능한 모든 서버리스 데이터베이스를 비교하는 이 기사를 확인할 수도 있습니다.

Upstash와 함께

  • 무료로 시작하고 사용한 만큼만 비용을 지불합니다.
  • 빠르고 내구성 있는 저장 장치
  • 글로벌 데이터베이스 및 에지 캐싱 덕분에 대기 시간이 짧고 전 세계 어디에서나 데이터베이스에 액세스할 수 있습니다.

지금 무료로 Upstash를 시작하세요

Upstash에서 애플리케이션을 효과적으로 구축하려면 Redis를 이해해야 합니다. Redis에 대해 간략히 소개하고 Upstash 앱 내에서 Redis를 사용하는 방법을 살펴보는 것이 좋습니다.

좀 더 자세하고 깊이 있는 것을 원하신다면 공식 Redis 웹사이트를 추천합니다.

Redis는 데이터베이스, 캐시 및 메시지 브로커로 사용되는 오픈 소스(BSD 라이선스), 인메모리 데이터 구조 저장소입니다.

다음과 같은 수많은 데이터 구조를 지원합니다.

  • 문자열
  • 해시
  • 목록
  • 세트
  • 범위 쿼리가 있는 정렬된 세트
  • 비트맵
  • 하이퍼로그
  • 지리공간 색인

명령을 사용하여 Redis 데이터베이스와 상호 작용하고 키 값 형식으로 데이터를 저장합니다. 여기서 키는 문자열과 값, Redis에서 지원하는 모든 데이터 구조가 될 수 있습니다.

예를 들어 Redis 명령 SET을 사용할 수 있습니다. 이렇게 내 성의 가치를 저장하기 위해

SET surname Rosius

여기서 핵심이고 Rosius가 가치입니다.

Redis에서 주의해야 할 한 가지 매우 중요한 사항은 항상 쉽게 검색할 수 있는 방식으로 데이터를 저장한다는 것입니다.

Redis에서 값으로 키를 검색하는 직접적인 방법은 없습니다.

Redis의 데이터는 영구적으로 저장됩니다. 따라서 surname 키에 저장된 데이터를 검색할 수 있습니다. 그렇게

GET surname

'Rosius'에 대한 결과

surname 키에 저장된 값을 삭제할 수도 있습니다. 그렇게

DEL surname

게시물의 좋아요를 늘리고 싶다고 가정해 보겠습니다. INCR을 사용하여 쉽게 할 수 있는 방법은 다음과 같습니다. 원자적 명령입니다.

SET likes 10
INCR likes => 11
INCR likes => 12
INCR likes => 13

먼저 likes의 초기 값을 10으로 설정한 다음 likes 값을 원자적으로 증가시킵니다. 이제 likes도 증가할 수 있다고 생각할 것입니다. 이쪽으로.

x = GET likes
x = x + 1
SET likes x

당신이 당신의 애플리케이션을 사용하는 유일한 사람이라면 이것은 완전히 괜찮습니다. 이것은 옳은 경우가 결코 아닙니다.

2명 이상이 동일하게 증가하면 위의 프로세스(GET,Increment,SET)는 더 이상 원자적이지 않습니다. 따라서

x = GET likes (yields 10)
y = GET likes (yields 10)
x = x + 1 (x is now 11)
y = y + 1 (y is now 11)
SET likes x (likes is now 11)
SET likes y (likes is now 11

위의 코드에서 사용자 1은 10인 likes 값을 가져와 변수 x에 저장하고 동시에 사용자 2는 같은 값인 10을 가져와 변수에 저장합니다. 예.

사용자 1은 likes(x)의 값에 1을 추가하고 새 값을 설정합니다. 이제 11이 됩니다.

사용자 2도 마찬가지입니다.

따라서 좋아요의 값은 11입니다.

그런데 그게 정말 맞습니까? 좋아요는 2명의 다른 사용자에 의해 두 번 증가했음을 기억하십시오.

좋아요의 값은 11이 아니라 12여야 합니다. 이것이 Redis가 INCR을 제공하는 이유입니다. 원자적이며 이러한 문제를 해결하는 명령입니다.

해시 데이터 유형

Redis 해시는 다른 프로그래밍 언어의 해시와 동일합니다. 기본적으로 값과 관련된 필드 모음으로 구성됩니다.

예를 들어 사용자 프로필 정보를 해시에 저장하는 방법은 다음과 같습니다.

HMSET userProfile:100034  "userId" 100034 "username" "Rosius Ndimofor"
            "firstName" "Rosius" "lastName" "Ndimofor" "profilePic" "rosius.jpeg"

첫째, 해시의 키는 userProfile:100034입니다. , 그러면 키 값이 있습니다. 모두 짝을 이룬다. 예:"userId" 는 키이고 100034'는 값입니다. 를 사용하여 이름과 같은 특정 사용자 프로필 정보를 검색할 수 있습니다. HGET명령 및 userId`와 같습니다.

userId = 100034
HGET userProfile:{userId} firstName

또는 GETALL을 사용하여 특정 사용자에 대한 모든 사용자 프로필 정보를 검색할 수 있습니다. 그렇게 명령하십시오

userId = 100034
HGETALL userProfile:{userId}

목록 데이터 유형

앞서 Redis에서는 데이터를 검색하려는 방식으로 저장하는 것이 매우 중요하다고 말했습니다.

플랫폼의 모든 사용자를 확보하려면 어떻게 해야 합니까?

사용자 프로필 정보를 저장하기 위해 해시 데이터 구조를 사용했습니다. 이제 시스템의 모든 사용자를 가져와야 합니다.

이를 수행하는 가장 쉬운 방법은 다음과 같이 LPUSH(왼쪽 푸시를 나타냄) 명령을 사용하여 목록에 있는 모든 사용자의 userId를 저장하는 것입니다.

LPUSH "users" userId

목록에서 모든 사용자를 가져오기 위해 LRANGE 명령을 사용합니다. 그렇게

LRANGE  "users" 0  -1

이것들은 우리 애플리케이션에서 사용할 몇 가지 명령에 불과합니다. 하지만 Redis 공식 사이트를 방문하여 나머지 명령을 보고 사용법을 익히길 권합니다.

풀스택 애플리케이션은 어떻게 작동할까요?

물어봐주셔서 기쁩니다. 그래서 오늘은 CRUD API를 만드는 것부터 시작하겠습니다. 다음은 사용 사례입니다.

2개의 엔티티가 있습니다. 사용자게시물 .

그들은 일대다 관계를 공유합니다. 따라서 한 사용자는 여러 게시물을 가질 수 있으며 하나의 게시물은 한 사용자에게만 속할 수 있습니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

사용자가 허용됨

  • 계정을 만드십시오. 인증이 없습니다. AWS Cognito 또는 Auth0을 사용하여 인증을 추가할 수 있습니다.
  • 계정 업데이트
  • 계정 가져오기
  • 게시물 작성
  • 게시물 업데이트
  • 게시물 좋아요
  • 모든 게시물 목록 가져오기

다음은 솔루션 아키텍처 보기입니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부 시작하겠습니다.

Upstash 계정 만들기

여기에서 무료 Upstash 계정을 만드십시오. Upstash 로그인

계정 생성 후 Upstash 데이터베이스를 생성합니다.

프리 티어에서는 하나의 데이터베이스만 생성할 수 있습니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부 Redis 데이터베이스 끝점을 기록해 둡니다. 다음과 같이 보일 것입니다.rediss://:2c9bb162c2444bf7ab689640bb2ead23@gusc1-smashing-bee-30249.upstash.io:00049

서버리스 프로젝트 만들기

전제 조건

계속하기 전에 이러한 종속성을 설치하십시오.

  • AWS CLI

  • 노드JS

  • 서버리스 CLI

    아래 명령을 사용하고 프롬프트에 따라 새 서버리스 프로젝트를 만듭니다.

serverless

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

nodejs HTTP API를 선택하고 프로젝트 이름을 지정한 다음 enter를 누르십시오. .

다음은 제 서버리스 프로젝트의 초기 구조입니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

해당 폴더 내에서 명령을 사용하여 새 노드 프로젝트를 초기화합니다.

npm init

다음으로

를 사용하여 redis 클라이언트를 설치합니다.
npm install ioredis

또한 보편적으로 고유한 Identifier(uuid) 종속성을 설치하십시오. 이 프로젝트에서 광범위하게 사용할 것입니다.

npm install uuid

이제 serverless.yml에 Redis 데이터베이스 엔드포인트를 환경 변수로 추가합니다. 이렇게 파일을 만드세요.

provider:
  name: aws
  region: us-east-1
  stage: dev
  runtime: nodejs12.x
  lambdaHashingVersion: "20201221"
  environment:
    REDIS_CLIENT: "rediss://:2c9bb162c2444bf7ab689640bb2ead23@gusc1-smashing-wasp-30249.upstash.io:30249"

다음으로 프로젝트 내에 users라는 폴더 2개를 만듭니다. 및 게시물 . 이 두 폴더 모두 각각의 사용 사례에 대한 람다 함수를 보유합니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

API 엔드포인트 생성을 시작해 보겠습니다.

사용자 생성

우리는 사용자가 스스로 계정을 만들 수 있기를 바랍니다.

인증이 없습니다. 제출하기만 하면

  • 사용자 이름
  • 이름
  • 프로필 사진

user에서 파일 생성 create.js라는 폴더 .

파일 상단에서 serverless.yml에 환경 변수로 저장한 redis 데이터베이스 URL을 사용하여 redis 클라이언트를 가져오고 인스턴스화합니다. 파일.

"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

또한 사용자의 고유 ID를 만드는 데 사용할 uuid 종속성을 가져옵니다.

먼저 사용자 프로필을 저장하기 위한 데이터 구조가 필요합니다. 정보 및 userId를 저장하기 위한 다른 데이터 구조 애플리케이션의 모든 사용자 수

해시 및 목록 데이터 유형을 기억하십니까?

사용자 프로필 정보를 저장하기 위한 해시 데이터 유형입니다. 데이터 유형 키 userItem:${userId}를 기록해 둡니다.

await client.hmset(
  `userItem:${userId}`,
  "userId",
  userId,
  username,
  data.username,
  firstName,
  data.firstName,
  lastName,
  data.lastName,
  profilePic,
  data.profilePic,
  "timestamp",
  timestamp
);

그런 다음 생성된userId를 저장합니다. users라는 목록에

await client.lpush("users", userId);

눈치채셨다면 2개의 작업을 보내야 합니다. 차례로 보낼 수는 있지만 최적의 방법은 아닙니다.

Upstash는 파이프라인이라는 기능을 통해 일괄 작업을 지원합니다. .

따라서 단일 명령을 보내고 응답을 기다리는 대신 여러 명령을 보낼 수 있으며 명령을 보낸 것과 같은 방식으로 응답이 돌아옵니다.

파이프라인을 사용한 후의 작업은 다음과 같습니다.

client.pipeline(
  await client.hmset(
    `userItem:${userId}`,
    "userId",
    userId,
    username,
    data.username,
    firstName,
    data.firstName,
    lastName,
    data.lastName,
    profilePic,
    data.profilePic,
    "timestamp",
    timestamp
  ),
  await client.lpush("users", userId)
);

그런 다음 모든 사용자 저장 프로필 정보를 가져와 api-gateway를 통해 응답으로 반환할 수 있습니다. .

//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

serverless.yml 업데이트를 잊지 마세요. 이 끝점을 반영합니다.

functions:
  createUser:
    handler: user/create.createUser
    events:
      - http:
          path: /user
          method: post

함수 이름은 createUser입니다. , 그리고 create.js라는 파일에 있습니다. user라는 폴더 안에 있습니다. .따라서 핸들러 user/create.createUser .

/user 경로를 기록해 둡니다.

createUser 함수는 post를 사용합니다. http 방법.

다음은 users/create.js의 전체 코드입니다. 파일

"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
const username = "username";
const firstName = "firstName";
const lastName = "lastName";
const profilePic = "profilePic";

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

/**
 *
 * @param {username,firstName,lastName,profilePic} event
 * @returns
 */
module.exports.createUser = async (event) => {
  const timestamp = new Date().getTime();

  const data = JSON.parse(event.body);
  if (data == null) {
    return {
      statusCode: 400,
      body: JSON.stringify(
        {
          message: "Couldn't create the user item",
        },
        null,
        2
      ),
    };
  }

  const userId = uuid.v1();
  console.log(`userId is ${userId}`);
  // here, we use a pipeline to perform multiple requests
  // Firstly, we save the user details to a hash dataset with key (`userItem:${userId}`)
  //
  client.pipeline(
    await client.hmset(
      `userItem:${userId}`,
      "userId",
      userId,
      username,
      data.username,
      firstName,
      data.firstName,
      lastName,
      data.lastName,
      profilePic,
      data.profilePic,
      "timestamp",
      timestamp
    ),
    await client.lpush("users", userId)
  );

  //get and display saved user item
  const userItem = await client.hgetall(`userItem:${userId}`);

  console.log(userItem);

  return {
    statusCode: 200,
    body: JSON.stringify(userItem),
  };
};

사용자 업데이트

사용자는 때때로 자신의 프로필을 업데이트하기를 원합니다. 따라서 사용자 업데이트 엔드포인트를 제공하는 것이 맞습니다.

이 작업에 필요한 유일한 명령은 HMSET입니다. 명령 및 userId .

Redis 문서에서 HMSET 명령이 작동합니다.

<블록 인용>

지정된 필드를 키에 저장된 해시의 해당 값으로 설정합니다. 이 명령은 해시에 이미 존재하는 모든 지정된 필드를 덮어씁니다.

코드는 다음과 같습니다.

"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
const username = "username";
const firstName = "firstName";
const lastName = "lastName";

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

/**
 *
 * @param {username,firstName,lastName,age,profilePic} event
 * @returns
 */
module.exports.updateUser = async (event) => {
  const timestamp = new Date().getTime();
  const userId = event.pathParameters.id;
  const data = JSON.parse(event.body);
  if (userId == null) {
    return {
      statusCode: 400,
      body: JSON.stringify(
        {
          message: "Couldn't update the user item",
        },
        null,
        2
      ),
    };
  }

  //get

  await client.hmset(
    `userItem:${userId}`,
    username,
    data.username,
    firstName,
    data.firstName,
    lastName,
    data.lastName
  );

  //get and display saved user item
  const userItem = await client.hgetall(`userItem:${userId}`);

  console.log(userItem);

  return {
    statusCode: 200,
    body: JSON.stringify(userItem),
  };
};

그런 다음 serverless.yml에서 파일, 기능 아래에 추가...

updateUser:
  handler: user/update.updateUser
  events:
    - http:
        path: /user/{id}
        method: put

userId를 전달합니다. 경로 매개변수로 /user/{id}

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

사용자 가져오기

HGETALL 사용 명령과 해시 키를 사용하여 특정 사용자에 대한 사용자 프로필 정보를 얻을 수 있습니다.

HGET도 사용할 수 있습니다. firstName 또는 lastName 등과 같은 사용자 특정 정보를 가져오는 명령입니다.

코드를 보자

user에서 파일 생성 get.js라는 폴더

"use strict";
var Redis = require("ioredis");

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

module.exports.getUserById = async (event) => {
  const userId = event.pathParameters.id;

  if (userId == null) {
    return {
      statusCode: 400,
      body: JSON.stringify(
        {
          message: "Couldn't get the user item",
        },
        null,
        2
      ),
    };
  }

  console.log(`userId is ${userId}`);

  //get and display saved user item
  const userItem = await client.hgetall(`userItem:${userId}`);

  console.log(userItem);

  return {
    statusCode: 200,
    body: JSON.stringify(userItem),
  };
};

그런 다음 serverless.yml에서 파일,

getUser:
  handler: user/get.getUserById
  events:
    - http:
        path: /user/{id}
        method: get

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

사용자 나열

사용자 생성을 위한 핸들러를 작성할 때 push(LPUSH ) userId는 users로 목록.

이제 LRANGE 명령을 사용하여 모든 ID를 가져와야 합니다. .

<블록 인용>

참고:LRANGE는 게시물 목록이 매우 커지기 시작하고 목록 중간에 있는 요소에 액세스하려는 경우 매우 효율적이지 않습니다. Redis 목록은 연결 목록으로 뒷받침되기 때문입니다. 시스템이 백만 개의 항목에 대한 깊은 페이지 매김을 위해 설계된 경우 대신 Sorted Sets에 의존하는 것이 좋습니다.

모든 userId를 얻은 후 각 id를 반복할 수 있습니다. HGETALL를 사용하여 사용자 프로필 정보를 가져옵니다. .

이것이 코드에서 어떻게 보이는지 봅시다.

"use strict";
var Redis = require("ioredis");

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

module.exports.getAllUsers = async (event) => {
  let users = [];
  let response = await client.lrange("users", 0, -1);

  async function getAllUsers() {
    let users = [];

    await Promise.all(
      response.map(async (userId) => {
        const item = await client.hgetall(`userItem:${userId}`);
        users.push(item);
        console.log(users);
      })
    );

    return users;
  }
  users = await getAllUsers();

  return {
    statusCode: 200,
    body: JSON.stringify(users),
  };
};

그런 다음 serverless.yml에 대해

listUsers:
  handler: user/list.getAllUsers
  events:
    - http:
        path: /users
        method: get

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

이것이 사용자를 위한 것입니다. 끝점. 아직 수행하지 않았다면 앱을 배포할 수 있습니다.

sls deploy

게시물

사용자가 계정을 만든 후에는

  • 게시물 작성
  • Id로 게시물 받기
  • 게시물 목록 가져오기
  • 게시물에 좋아요 또는 싫어요(게시물에 반응)

시작하겠습니다.

게시물 만들기

게시물을 만드는 데 필요한 매개변수는

  • 사용자 ID
  • postId(UUID에 의해 자동 생성됨)
  • 포스트텍스트
  • 포스트 이미지
  • 만든 날짜

3단계가 필요합니다.

  1. HMSET 명령을 사용하여 게시물 세부정보를 해시 키로 설정합니다. postItem:${postId} .
  2. LPUSH 명령을 사용하여 게시물 목록에 postId 추가 .
  3. LPUSH 명령을 사용하여 userPost:${userId} 목록에 postId를 추가합니다. .

파이프라인을 사용하여 이 작업을 시간순으로 실행합니다.

게시물에 파일 만들기 create.js라는 폴더 다음 코드를 추가하세요.

"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

/**
 *
 * @param {userId,postId,postText,postImage,createdOn} event
 * @returns
 */
module.exports.createPost = async (event) => {
  const timestamp = new Date().getTime();
  const postId = uuid.v1();
  const data = JSON.parse(event.body);
  if (data == null) {
    return {
      statusCode: 400,
      body: JSON.stringify(
        {
          message: "Couldn't create the Post item",
        },
        null,
        2
      ),
    };
  }

  console.log(`postId is ${postId}`);

  client.pipeline(
    await client.hmset(
      `postItem:${postId}`,
      "id",
      postId,
      "userId",
      data.userId,
      "postText",
      data.postText,
      "postImage",
      data.postImage,
      "createdOn",
      timestamp
    ),
    await client.lpush("posts", postId),
    await client.lpush(`userPost:${data.userId}`, postId)
  );

  //get and display saved post item
  const postItem = await client.hgetall(`postItem:${postId}`);

  console.log(postItem);

  return {
    statusCode: 200,
    body: JSON.stringify(postItem),
  };
};

그런 다음 serverless.yml의 함수 아래에서 , 추가

createPost:
  handler: post/create.createPost
  events:
    - http:
        path: /post
        method: post

배포하고 테스트합니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

ID로 게시물 가져오기

Id로 게시물을 가져올 때 게시물 관리자의 세부 정보를 가져와 지금까지 게시물의 반응(좋아요) 수와 함께 첨부하려고 합니다.

아직 게시물에 좋아요 또는 싫어요를 표시하지 않았다는 것을 알고 있습니다. 잠시만 기다려 주십시오. 이제 완료됩니다.get.js라는 파일을 생성합니다. 게시물 폴더에 저장하고

"use strict";
var Redis = require("ioredis");

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

module.exports.getPostById = async (event) => {
  const postId = event.pathParameters.id;
  if (postId == null) {
    return {
      statusCode: 400,
      body: JSON.stringify(
        {
          message: "Couldn't get the post item",
        },
        null,
        2
      ),
    };
  }

  console.log(`postId is ${postId}`);

  //get and display saved post item
  const postItem = await client.hgetall(`postItem:${postId}`);
  const userItem = await client.hgetall(`userItem:${postItem.userId}`);
  const postReactionsCount = await client.get(`postReactionsCount:${postId}`);
  postItem["postAdmin"] = userItem;
  postItem["reactionCount"] =
    postReactionsCount == null ? 0 : postReactionsCount;
  console.log(postItem);
  console.log(userItem);

  return {
    statusCode: 200,
    body: JSON.stringify(postItem),
  };
};

위의 코드에서 먼저 hgetall을 사용하여 특정 게시물에 대한 모든 게시물 세부정보를 얻습니다. 명령 및 키 postItem:${postId} .

그러면 게시물 객체에 게시물을 작성한 사용자(post admin)의 userId가 있으므로 userItem:${postItem.userId}를 사용합니다. 해당 사용자에 대한 사용자 세부 정보를 가져옵니다.

이것은 위의 사용자 엔드포인트 생성에서 사용한 것과 정확히 동일한 키임을 기억하십시오.

세 번째로 get을 사용하여 postReactionCount를 얻습니다. 명령 및 키 postReactionsCount:${postId} 나중에 postReactionsCount를 저장하는 데 사용할 것입니다.

배포 및 테스트

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

게시물에 반응하기

이것은 전체 응용 프로그램의 가장 흥미로운 끝점입니다. 글을 쓰는 것이 즐거웠습니다.

사용자는 게시물을 좋아하거나 싫어할 수 있습니다. 이제 사용자가 좋아요 버튼을 클릭하면 이 사용자가 이전에 게시물을 좋아했는지 먼저 확인합니다.

그렇다면 우리는 게시물과 다릅니다. 그렇지 않으면 게시물이 마음에 듭니다.

이해가 되셨나요?

인스타그램이나 트위터처럼.

react_to_post.js라는 게시물 폴더에 파일을 만듭니다.

엔드포인트는 userId를 사용합니다. 및 postId 경로 매개변수로.

새로운 명령을 살펴보자. 정렬된 집합입니다. 정렬된 집합을 사용하여 게시물에 좋아요를 표시한 사용자의 userId와 게시물을 좋아했을 때의 타임스탬프를 추가합니다.

zadd(`postReactions:${postId}`, timestamp, data.userId)

키는 postReactions:${postId}입니다. .

정렬된 세트는 Z로 시작합니다. Redis 문서에서 zadd

<블록 인용>

key에 저장된 정렬된 집합에 지정된 점수를 가진 지정된 모든 멤버를 추가합니다. 여러 점수/구성원 쌍을 지정할 수 있습니다. 지정된 구성원이 이미 정렬된 집합의 구성원인 경우 올바른 순서를 보장하기 위해 점수가 업데이트되고 요소가 올바른 위치에 다시 삽입됩니다.

다음 단계는 를 사용하여 postReactionsCount:${postId}를 증가시키는 것입니다. incr` 명령.

Post by Id 엔드포인트에서 위의 키를 사용하여 사후 반응 수를 얻었음을 기억하십시오.

incr(`postReactionsCount:${postId}`),

마지막으로 사용자 게시물 반응 세부정보를 해시에 저장합니다.

hmset(`userPostReactions:${data.userId}`,
                "postId", postId,
                "userId", data.userId,
                "timestamp", timestamp
            ),

이 모든 것을 바탕으로 사용할 수 있는 액세스 패턴은 다음과 같습니다.

  • 후기 반응 수를 얻을 수 있습니다.
  • 게시물에 반응한 모든 사용자를 오름차순 또는 내림차순으로 가져올 수 있습니다.
  • 사용자가 반응한 모든 게시물을 확인할 수 있습니다.

우리는 이전에 사용자가 게시물을 좋아했는지 확인하기 위해 확인해야 한다고 앞서 언급했습니다. 그렇다면 해당 게시물을 싫어합니다. 게시물이 마음에 들지 않으면

zscore를 사용하겠습니다. 이를 위한 명령입니다.

<블록 인용>

key에 있는 정렬된 집합의 구성원 점수를 반환합니다. 정렬된 집합에 구성원이 없거나 키가 없는 경우 nil이 반환됩니다.

zscore(`postReactions:${postId}`, data.userId);

zscore인 경우 null이면 사용자가 이 항목을 좋아하지 않습니다. 그렇지 않으면 사용자가 좋아합니다.

전체 코드는 다음과 같습니다.

"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");

if (typeof client === "undefined") {
  var client = new Redis(process.env.REDIS_CLIENT);
}

/**
 *
 * @param {userId,postId,postText,postImage,createdOn} event
 * @returns
 */
module.exports.reactToPost = async (event) => {
  const timestamp = new Date().getTime();

  const data = JSON.parse(event.body);
  const postId = event.pathParameters.id;

  if (data == null || postId == null) {
    return {
      statusCode: 400,
      body: JSON.stringify(
        {
          message: "Couldn't react to the Post",
        },
        null,
        2
      ),
    };
  }

  console.log(`postId is ${postId}`);
  console.log(`userId is ${data.userId}`);
  // first check if user has already liked the post
  const hasUserReacted = await client.zscore(
    `postReactions:${postId}`,
    data.userId
  );
  if (hasUserReacted == null) {
    //user hasn't reacted.
    client.pipeline(
      await client.incr(`postReactionsCount:${postId}`),
      await client.zadd(`postReactions:${postId}`, timestamp, data.userId),
      await client.hmset(
        `userPostReactions:${data.userId}`,
        "postId",
        postId,
        "userId",
        data.userId,
        "timestamp",
        timestamp
      )
    );
  } else {
    //user already reacted, so unreact
    client.pipeline(
      await client.decr(`postReactionsCount:${postId}`),
      await client.zrem(`postReactions:${postId}`, data.userId),
      await client.hdel(
        `userPostReactions:${data.userId}`,
        "postId",
        postId,
        "userId",
        data.userId,
        "timestamp",
        timestamp
      )
    );
  }

  //return the post reaction count
  const postReactionsCount = await client.get(`postReactionsCount:${postId}`);

  console.log(postReactionsCount);

  return {
    statusCode: 200,
    body: JSON.stringify({
      postReactionCount: parseInt(postReactionsCount),
    }),
  };
};

그런 다음 serverless.yml에서

reactToPosts:
  handler: post/react_to_post.reactToPost
  events:
    - http:
        path: /post/{id}/react
        method: post

배포하고 테스트합니다.

Flutter, Serverless Framework 및 Upstash(REDIS)가 포함된 Fullstack 서버리스 앱 - 1부

API 테스터(저는 PostMan을 사용합니다)에서 보내기 버튼을 여러 번 누르고 "postReactionCount"가 0과 1 사이에서 어떻게 전환되는지 확인하세요.

UserId를 변경하고 다시 확인하십시오.

이 API에 추가할 수 있는 다른 액세스 패턴과 수정 사항이 많이 있습니다.

이 문제를 확장하고 자세히 알아보기 위해 도전하는 것은 어떻습니까?

전체 소스 코드에 대한 링크는 다음과 같습니다.

나는 Redis의 그다지 가파르지 않은 학습 곡선과 데이터를 검색하는 방식으로 데이터를 저장할 수 있다는 사실을 절대적으로 좋아합니다.

앱 개발을 시작하기 전에 항상 액세스 패턴을 파악하세요.

저는 이 글을 쓰는 것이 매우 즐거웠습니다. 여러분이 한두 가지를 배웠기를 바랍니다.

내가 어딘가에서 실수를 했습니까? 당신과 같은 슈퍼 사얀은 주저하지 않고 저에게 알려줄 것입니다.

다음 기사에서는 이 API를 사용하는 Flutter 앱을 빌드할 것입니다. 계속 지켜봐 주십시오.

해피 코딩 동지✌🏿

참조

  • Upstash 문서
  • 레디스
  • 플러터
  • 인터넷에서 데이터 가져오기