GraphQL을 통해 RejectionDB의 실시간 마법을 전방으로 가져오기
RejectionDB는 실시간 문서 데이터베이스입니다.MongodB와 마찬가지로 사용하기 쉽고 모드가 없습니다.또한 조회를 구독하고 데이터가 바뀔 때 알림을 받을 수 있어 실시간 응용 프로그램의 완벽한 선택이 될 수 있습니다.
You can also try the running app, or check out the code repository.
응용 프로그램 설정
우리는 노드를 세울 것이다.js 응용 프로그램이기 때문에 설치
node
와 npm
가 필요합니다.히로쿠에 응용 프로그램을 배치하려면 Heroku account와 그들의 CLI를 설치해야 한다.응용 프로그램을 로컬에서 실행하려면 install and run a RethinkDB instance가 필요합니다.우리는 간단한 노드를 사용할 것이다.js 서버 및 Vuejs 전단.프런트엔드를 구축해야 하므로 Vue CLI를 사용하여 Vue 애플리케이션을 만듭니다.
$ vue create -d rethink-chat
$ cd rethink-chat
이렇게 하면 노드 항목이 생성되고 Vue가 생성됩니다.js 프레임워크와git 저장소를 초기화합니다.Heroku 어플리케이션 준비
Heroku에 응용 프로그램을 배치하려면 다음과 같은 Heroku 응용 프로그램을 만들어야 합니다.
$ heroku create
사용자 간에 보내는 채팅 정보를 저장하고 구독하기 위한 RejectDB 실례가 필요합니다.RethinkDB Cloud add-on에서 다음을 수행할 수 있습니다.$ heroku addons:create rethinkdb
The RethinkDB Cloud add-on is currently in alpha. Request an invite for your Heroku account email.
서버 구축
우리는
server
디렉터리에 서버를 만들 것이다.먼저 디렉토리를 만들고 필요한 종속성을 설치합니다.$ mkdir server
$ npm install rethinkdb apollo-server-express graphql morgan lorem-ipsum
이제 노드를 설정합니다.js 서버.index.js
파일을 만들고 다음 서버 프레임워크를 추가합니다.우리는 급행열차를 쓴다.js 서버는 전방에 서비스되고 Apollo GraphQL 서버는 채팅 정보를 방문하고 구독하는 데 사용됩니다.// server/index.js
// Setup Express server
const express = require("express");
const app = express();
const http = require("http").createServer(app);
// Logging middleware
var morgan = require("morgan");
app.use(morgan("combined"));
// Serve frontend
app.use(express.static("dist"));
// Lazy RethinkDB connection
// ...
// Setup Apollo (GraphQL) server
// ...
// HTTP server (start listening)
const listenPort = process.env.PORT || "3000";
http.listen(listenPort, () => {
console.log("listening on *:" + listenPort);
});
이 뼈대는 dist
폴더의 정적 전단이다.이것이 바로 컴파일된 Vue가 있는 위치입니다.우리는 잠시 후에 js 프로그램을 만들 것입니다.그리고 우리 서버는 세 가지 일을 해야 한다.데이터베이스 연결 재정의
우리는 데이터베이스 연결을 게으름 피우며 관리한다. 즉, 우리는 실제 필요할 때만 (다시) 연결을 만든다는 것이다.연결 매개 변수는 환경 변수에서 해석되거나 기본값을 사용합니다.
// server/index.js
// ...
// Lazy RethinkDB connection
var r = require("rethinkdb");
let rdbConn = null;
const rdbConnect = async function () {
try {
const conn = await r.connect({
host: process.env.RETHINKDB_HOST || "localhost",
port: process.env.RETHINKDB_PORT || 28015,
username: process.env.RETHINKDB_USERNAME || "admin",
password: process.env.RETHINKDB_PASSWORD || "",
db: process.env.RETHINKDB_NAME || "test",
});
// Handle close
conn.on("close", function (e) {
console.log("RDB connection closed: ", e);
rdbConn = null;
});
console.log("Connected to RethinkDB");
rdbConn = conn;
return conn;
} catch (err) {
throw err;
}
};
const getRethinkDB = async function () {
if (rdbConn != null) {
return rdbConn;
}
return await rdbConnect();
};
Heroku에서 DB Cloud 플러그인은 환경 변수를 설정합니다.로컬에서 실행되는 RejectDB 인스턴스의 경우 기본값을 사용할 수 있어야 합니다.Apollo GraphQL 서버 설정
앞에서 말한 바와 같이 앞부분은 정적이다.그러나 우리는 채팅방의 데이터를 방문해야 한다.이것은 가장 자주 사용하는 GraphQL 서버 Apollo에서 처리될 것입니다.
// server/index.js
// ...
// Setup Apollo (GraphQL) server
const { ApolloServer } = require("apollo-server-express");
const { typeDefs, resolvers } = require("./schema.js");
const graphqlServer = new ApolloServer({
typeDefs,
resolvers,
context: async (arg) => {
const conn = await getRethinkDB();
return {
conn: conn,
};
},
});
graphqlServer.applyMiddleware({ app });
graphqlServer.installSubscriptionHandlers(http);
이것은 패턴 파일 (다음 절) 에 정의된 형식 정의와 해석을 사용하여 Apollo 서버를 만들 것입니다.또한 RejectDB에 연결하여 GraphQL 상하문에 연결을 전달하여 모든 전송 요청에서 사용할 수 있도록 합니다.GraphQL 모드 만들기
서버의 주요 논리는GraphQL 유형을 정의하고 이를 실현하는 해상도입니다.우리는 세 가지 다른 조작을 실행할 수 있어야 한다. 즉,
Chat
메시지 유형과 상기 세 가지 조작, 즉 chats
조회, sendChat
변이와 chatAdded
구독을 포함한다.// server/schema.js
// GraphQL type definitions
const { gql } = require("apollo-server-express");
exports.typeDefs = gql`
type Chat {
user: String
msg: String
roomId: String
ts: Float
}
type Query {
chats(room: String!): [Chat]
}
type Mutation {
sendChat(user: String!, message: String!, room: String!): Chat
}
type Subscription {
chatAdded(room: String!): Chat
}
`;
// GraphQL resolvers
// ...
그 다음으로 우리는 이 조작, 즉 호출된 코드를 실현하는 것을 해결해야 한다.조회와 변이는 매우 간단하여 간단한 조회로 실현할 수 있다.그러나 구독은 비동기 교체기가 필요합니다.기본적으로 RejectionDB 마법을GraphQL 구독 마법으로 바꿀 수 있는 주문이다.더욱 현실적인 의미에서, 비동기 교체기는 데이터베이스 변경 요약을 포장하여GraphQL을 통해 구독할 수 있도록 한다.// server/schema.js
// GraphQL type definitions
// ...
// GraphQL resolvers
const r = require("rethinkdb");
exports.resolvers = {
Subscription: {
chatAdded: {
async subscribe(parent, args, context, info) {
return new RethinkIterator(
r.table("chats").filter({ roomId: args.room }),
context.conn,
);
},
},
},
Mutation: {
async sendChat(root, args, context) {
const chatMsg = {
user: args.user,
roomId: args.room,
msg: args.message,
ts: Date.now(),
};
await r.table("chats").insert(chatMsg).run(context.conn);
return chatMsg;
},
},
Query: {
async chats(parent, args, context, info) {
const cursor = await r
.table("chats")
.filter({ roomId: args.room })
.orderBy(r.desc("ts"))
.run(context.conn);
return await cursor.toArray();
},
},
};
// Async iterator to access the RethinkDB change feed
const { $$asyncIterator } = require("iterall");
class RethinkIterator {
constructor(query, conn) {
this.cursor = query.changes().run(conn);
}
async next() {
const val = await (await this.cursor).next();
return { value: { chatAdded: val.new_val }, done: false };
}
async return() {
await (await this.cursor).close();
return { value: undefined, done: true };
}
async throw(error) {
return Promise.reject(error);
}
[$$asyncIterator]() {
return this;
}
}
서버를 설정한 후, 우리는 앞쪽으로 돌아갑니다.프런트엔드 생성
Vue를 만들었습니다.우리는 전방의 js 응용 프로그램 프레임워크에 사용할 것입니다.그러나, 저희 서버가 표준적인GraphQL 백엔드를 실현했기 때문에, 당신은React나 다른GraphQL을 지원하는 백엔드 프레임워크를 사용할 수 있습니다.
우리의 앞부분은 두 개의 보기를 사용할 것이다. 하나는 홈페이지에 사용되고, 하나는 채팅방에 사용되며, 하나는 공유기가 둘 사이를 내비게이션할 것이다.이를 위해 Vue 프레임워크에 라우터를 추가하고 필요한 모든 종속성을 설치할 수 있습니다.Vue 애플리케이션에 라우터를 추가하면 변경 사항이 제한되지 않음을 경고하고 사용 내역 모드가 필요한지 여부를 묻습니다.
$ vue add router
$ npm install apollo-client apollo-link-http apollo-link-ws apollo-cache-inmemory vue-apollo
$ npm install sass sass-loader --save-dev
Google Vue 응용 프로그램은 src
폴더에 있습니다. 입구점은 main.js
에 있고 graphql.js
에서GraphQL 클라이언트 설정을 가져옵니다.우리의 메인 파일은 App.vue
마운트되어 있으며, 이 중 공유기가 router/index.js
에서 선택한 보기를 표시합니다.우리의 응용 프로그램은 두 개의 보기 views/Home.vue
와 views/ChatRoom.vue
를 포함한다.src
├── main.js
├── graphql.js
├── App.vue
├── router
│ └── index.js
└── views
├── Home.vue
└── ChatRoom.vue
기본 애플리케이션 및 라우터
우선, skeleton Vue 프로그램에서 초기화된 메인 프로그램, 메인 보기, 공유기 파일을 수정합니다.
main.js
에서 Apollo GraphQL 클라이언트를 가져왔습니다. 이 클라이언트를 더 정의하고 Vue 응용 프로그램에 추가할 것입니다.이 밖에 우리는 사용자를 위해 무작위 채팅 사용자 이름을 만들 것이다.// src/main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import apolloProvider from "./graphql";
Vue.config.productionTip = false;
// Initialize random username
window.username = Math.random().toString(36).substring(2, 8);
// Create and mount Vue app
new Vue({
router,
apolloProvider,
render: (h) => h(App),
}).$mount("#app");
우리의 App.vue
는 심지어 골격보다 더 간단하다. 그것은 공유기의 보기만 표시하고 스타일도 있다.<!-- src/App.vue -->
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: "App",
};
</script>
<style lang="scss">
// See styles at https://github.com/mostlytyped/rethink-chat-graphql/blob/master/src/App.vue
</style>
우리router/index.js
에서 우리는 기본적으로'방'노선으로'관'노선을 대체했다.// src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "@/views/Home";
import ChatRoom from "@/views/ChatRoom";
Vue.use(VueRouter);
const routes = [
{ path: "/", name: "Home", component: Home },
{ path: "/:roomId", name: "Room", component: ChatRoom },
];
const router = new VueRouter({
routes,
});
export default router;
메인 보기에서 HelloWorld
구성 요소를 삭제하고 방에 가입할 수 있는 폼을 추가합니다.<!-- src/views/Home.vue -->
<template>
<div class="main">
<form v-on:submit.prevent="gotoRoom">
<label>
Username:
<input v-model="user" type="text" />
</label>
<label>
Room:
<input v-model="room" type="text" />
</label>
<button>Join</button>
</form>
</div>
</template>
<script>
export default {
name: "Home",
data() {
return {
user: window.username,
room: "lobby",
};
},
methods: {
gotoRoom() {
window.username = this.user;
this.$router.push({
name: "Room",
params: { roomId: this.room },
});
},
},
};
</script>
<style scoped lang="scss">
// See styles at https://github.com/mostlytyped/rethink-chat-graphql/blob/master/src/views/Home.vue
</style>
이제 필요한 세션으로 프레임워크를 채워서, 전방,GraphQL 클라이언트, 채팅방 보기의 진정한 내용을 처리합니다.GraphQL 클라이언트
현재 단말기가 불러올 때 GraphQL 클라이언트를 시작해야 합니다.우리의 예시에서, 우리는 Apollo를 사용합니다. 이것은 가장 자주 사용하는 GraphQL 클라이언트입니다. 이것은 좋은 Vue를 가지고 있습니다.js와
vue-apollo
패키지의 통합.// src/graphql.js
import Vue from "vue";
import VueApollo from "vue-apollo";
import ApolloClient from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
import { split } from "apollo-link";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";
Vue.use(VueApollo);
// HTTP connection to the API
const httpLink = createHttpLink({
// For production you should use an absolute URL here
uri: `${window.location.origin}/graphql`,
});
// Create the subscription websocket link
const wsLink = new WebSocketLink({
uri: `wss://${window.location.host}/graphql`,
options: {
reconnect: true,
},
});
// Split link based on operation type
const link = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink, // Send subscription traffic to websocket link
httpLink, // All other traffic to http link
);
// Create apollo client/provider with our link
const apolloClient = new ApolloClient({
cache: new InMemoryCache(),
link: link,
});
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
});
export default apolloProvider;
GraphQL 구독을 사용할 것이기 때문에, Apollo 설정은 평소보다 좀 복잡합니다.정상적인 GraphQL은 HTTP를 통해 실행해야 하지만 구독 업데이트는 웹소켓을 통해 전송되기 때문이다.채팅방 보기
앞면의 마지막 부분은
ChatRoom
보기가 될 것이다.여기서 우리는 실제적으로 우리가 방금 초기화한 GraphQL 클라이언트를 사용할 수 있다.이 보기는 기본적으로 chats
변수의 모든 항목을 포함하고 백엔드에 채팅 정보를 보내는 목록을 보여 줍니다.<!-- src/views/ChatRoom.vue -->
<template>
<div class="chatroom">
<ul id="chatlog">
<li v-for="chat in chats" v-bind:key="chat.ts">
<span class="timestamp">
{{
new Date(chat.ts).toLocaleString(undefined, {
dateStyle: "short",
timeStyle: "short",
})
}}
</span>
<span class="user">{{ chat.user }}:</span>
<span class="msg">{{ chat.msg }}</span>
</li>
</ul>
<label id="username"> Username: {{ user }} </label>
<form v-on:submit.prevent="sendMessage">
<input v-model="message" autocomplete="off" />
<button>Send</button>
</form>
</div>
</template>
<script>
import gql from "graphql-tag";
export default {
name: "ChatRoom",
data() {
return {
chats: [],
message: "",
user: window.username,
handle: null,
};
},
methods: {
sendMessage() {
const msg = this.message;
this.$apollo.mutate({
mutation: gql`
mutation($user: String!, $msg: String!, $room: String!) {
sendChat(user: $user, room: $room, message: $msg) {
ts
}
}
`,
variables: {
user: this.user,
msg: msg,
room: this.$route.params.roomId,
},
});
this.message = "";
},
},
apollo: {
chats: {
query: gql`
query FetchChats($room: String!) {
chats(room: $room) {
msg
user
ts
}
}
`,
variables() {
return {
room: this.$route.params.roomId,
};
},
subscribeToMore: {
document: gql`
subscription name($room: String!) {
chatAdded(room: $room) {
msg
user
ts
}
}
`,
variables() {
return {
room: this.$route.params.roomId,
};
},
// Mutate the previous result
updateQuery: (previousResult, { subscriptionData }) => {
previousResult.chats.unshift(subscriptionData.data.chatAdded);
},
},
},
},
};
</script>
<style scoped lang="scss">
// See styles at https://github.com/mostlytyped/rethink-chat-graphql/blob/master/src/views/ChatRoom.vue
</style>
sendMessage
방법은 sendChat
GraphQL 돌연변이와 관련이 있다.chats
변수에 대해서는 귀속이 좀 복잡해야 한다.GraphQL chats
조회에 연결하고, 변수의 최신 상태를 유지하기 위해 chatAdded
구독을 사용합니다.현재 우리는 일하는 서버와 전방이 하나 있다.우리가 해야 할 마지막 일은 응용 프로그램을 실행할 때
chats
표가 데이터베이스에 실제로 존재하는지 확인하는 것이다.데이터베이스 마이그레이션
chats
표가 없어서 프로그램을 실행할 수 없습니다.따라서, 우리는 표를 추가한 데이터베이스 이전이 필요하다.// server/migrate.js
var r = require("rethinkdb");
r.connect(
{
host: process.env.RETHINKDB_HOST || "localhost",
port: process.env.RETHINKDB_PORT || 28015,
username: process.env.RETHINKDB_USERNAME || "admin",
password: process.env.RETHINKDB_PASSWORD || "",
db: process.env.RETHINKDB_NAME || "test",
},
function (err, conn) {
if (err) throw err;
r.tableList().run(conn, (err, cursor) => {
if (err) throw err;
cursor.toArray((err, tables) => {
if (err) throw err;
// Check if table exists
if (!tables.includes("chats")) {
// Table missing --> create
console.log("Creating chats table");
r.tableCreate("chats").run(conn, (err, _) => {
if (err) throw err;
console.log("Creating chats table -- done");
conn.close();
});
} else {
// Table exists --> exit
conn.close();
}
});
});
},
);
이 이전 검사 chats
표가 존재하는지 확인하고, 없으면 만듭니다.간단한 채팅 로봇
보시다시피 DBS의 중요한 특징은 베이킹의 반응성입니다. 이것은 우리가 조회를 구독할 수 있도록 합니다.간단한 채팅 로봇을 만들 때 이 기능도 매우 편리하다.bot은 구독
chats
표의 변경 사항을 구독하고 적당한 시기에 반응하기만 하면 됩니다.우리 로펌 로봇은
@lorem
의 프롬프트를 받으면 로펌 Ipsum에 무작위로 응답합니다.bot 구독 chats
표를 구독하고 메시지의 시작을 스캔합니다.@lorem
로 시작하면 같은 방에서 답장을 보냅니다.// server/lorem-bot.js
const LoremIpsum = require("lorem-ipsum").LoremIpsum;
const lorem = new LoremIpsum({
sentencesPerParagraph: {
max: 8,
min: 4,
},
wordsPerSentence: {
max: 16,
min: 4,
},
});
// Run Lorem bot
const runBot = function (conn) {
console.log("Lorem bot started");
r.table("chats")
.changes()
.run(conn, (err, cursor) => {
if (err) throw err;
cursor.each((err, row) => {
const msg = row.new_val.msg.trim().split(/\s+/);
// Is the message directed at me?
if (msg[0] === "@lorem") {
let num = 10;
if (msg.length >= 1) {
num = parseInt(msg[1]) || num;
}
r.table("chats")
.insert({
user: "lorem",
msg: lorem.generateWords(num),
roomId: row.new_val.roomId,
ts: Date.now(),
})
.run(conn, function (err, res) {
if (err) throw err;
});
}
});
});
};
// Connect to RethinkDB
const r = require("rethinkdb");
const rdbConnect = async function () {
try {
const conn = await r.connect({
host: process.env.RETHINKDB_HOST || "localhost",
port: process.env.RETHINKDB_PORT || 28015,
username: process.env.RETHINKDB_USERNAME || "admin",
password: process.env.RETHINKDB_PASSWORD || "",
db: process.env.RETHINKDB_NAME || "test",
});
// Handle close
conn.on("close", function (e) {
console.log("RDB connection closed: ", e);
setTimeout(rdbConnect, 10 * 1000); // reconnect in 10s
});
// Start the lorem bot
runBot(conn);
} catch (err) {
throw err;
}
};
rdbConnect();
Heroku에 응용 프로그램 배포
Heroku에 작업 프로그램과bot을 배치하려면
Procfile
을 만들어야 합니다.이 파일은 기본적으로 Heroku에게 어떤 프로세스를 실행해야 하는지 알려줍니다.// Procfile
release: node server/migrate.js
web: node server/index.js
lorem-bot: node server/lorem-bot.js
Heroku는 release
프로세스와 web
프로세스를 발표할 때 실행되는 명령과 메인 웹 프로그램으로 식별합니다.lorem-bot
프로세스는 작업 프로세스일 뿐 이름이 있을 수 있습니다.Heroku에 응용 프로그램 배포
$ git add .
$ git commit -m 'Working rethink-chat app'
$ git push heroku master
You will need to manually enable the
lorem-bot
process in your Heroku app. You can do so on the Resources tab.
결론
15분도 안 되는 시간에 우리는 간단한 로봇으로 채팅 프로그램을 만들고 배치했다.이것은 RejectDB의 강력한 기능과 사용 편의성을 보여 줍니다.구독 조회 능력은 반응식 응용 프로그램 구축을 쉽게 하고 GraphQL과 쉽게 통합할 수 있다.또한 Heroku는 배치를 쉽게 합니다. RejectionDB Cloud 추가 구성 요소가 있어서 데이터베이스 서버의 번거로운 작업을 직접 관리할 필요가 없습니다.
Reference
이 문제에 관하여(GraphQL을 통해 RejectionDB의 실시간 마법을 전방으로 가져오기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/saschat/bring-rethinkdb-s-realtime-magic-to-the-frontend-with-graphql-mn7텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)