Skip to content

Commit c436421

Browse files
committed
feat: apollo graphl link and server
Signed-off-by: Kevin Viglucci <[email protected]>
1 parent 7b1fe16 commit c436421

File tree

27 files changed

+1821
-16
lines changed

27 files changed

+1821
-16
lines changed

RELEASE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ How to publish new releases for this project.
88

99
You can either set versions in the `package.json` files manually, or use the `lerna version` command to set them via the Lerna CLI. When setting versions manually, you will also need to set the git tags for each package and version. For this reason, it is recommended you use the `lerna version` command, which will create these tags automatically.
1010

11-
ex: `@rsocket/[email protected]`
11+
ex: `rsocket-[email protected]`
1212

1313
Lerna will not push the git tags after creation. You should push the git tags once you are confident in your changes.
1414

packages/rsocket-examples/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,21 @@
1616
"start-client-server-request-response-tcp": "ts-node -r tsconfig-paths/register src/ClientServerRequestResponseExampleTcp.ts",
1717
"start-client-server-request-response-websocket": "ts-node -r tsconfig-paths/register src/ClientServerRequestResponseExampleWebSocket.ts",
1818
"start-client-server-composite-metadata-route": "ts-node -r tsconfig-paths/register src/ClientServerCompositeMetadataRouteExample.ts",
19-
"start-client-server-rx-composite-metadata-route": "ts-node -r tsconfig-paths/register src/rxjs/ClientServerCompositeMetadataRouteExample.ts"
19+
"start-client-server-rx-composite-metadata-route": "ts-node -r tsconfig-paths/register src/rxjs/ClientServerCompositeMetadataRouteExample.ts",
20+
"start-client-apollo-graphql": "ts-node -r tsconfig-paths/register src/graphql/apollo/client/example.ts",
21+
"start-client-server-apollo-graphql": "ts-node -r tsconfig-paths/register src/graphql/apollo/client-server/example.ts"
2022
},
2123
"dependencies": {
24+
"@apollo/client": "^3.5.10",
2225
"rsocket-adapter-rxjs": "^1.0.0-alpha.1",
2326
"rsocket-composite-metadata": "^1.0.0-alpha.1",
2427
"rsocket-core": "^1.0.0-alpha.1",
2528
"rsocket-tcp-client": "^1.0.0-alpha.1",
2629
"rsocket-tcp-server": "^1.0.0-alpha.1",
2730
"rsocket-websocket-client": "^1.0.0-alpha.1",
2831
"rsocket-websocket-server": "^1.0.0-alpha.1",
32+
"graphql-tag": "^2.12.6",
33+
"graphql-subscriptions": "^2.0.0",
2934
"ws": "~8.2.3"
3035
},
3136
"devDependencies": {
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Copyright 2021-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { RSocket, RSocketConnector, RSocketServer } from "rsocket-core";
18+
import { TcpClientTransport } from "rsocket-transport-tcp-client";
19+
import { TcpServerTransport } from "rsocket-transport-tcp-server";
20+
import { exit } from "process";
21+
import { makeRSocketLink } from "rsocket-graphql-apollo-link";
22+
import { ApolloServer } from "rsocket-graphql-apollo-server";
23+
import {
24+
ApolloClient,
25+
InMemoryCache,
26+
NormalizedCacheObject,
27+
} from "@apollo/client/core";
28+
import gql from "graphql-tag";
29+
import { resolvers } from "./resolvers";
30+
import { DocumentNode } from "@apollo/client";
31+
import * as fs from "fs";
32+
import path from "path";
33+
34+
let apolloServer: ApolloServer;
35+
let rsocketClient: RSocket;
36+
37+
function readSchema() {
38+
return fs.readFileSync(path.join(__dirname, "schema.graphql"), {
39+
encoding: "utf8",
40+
});
41+
}
42+
43+
function makeRSocketServer({ handler }) {
44+
return new RSocketServer({
45+
transport: new TcpServerTransport({
46+
listenOptions: {
47+
port: 9090,
48+
host: "127.0.0.1",
49+
},
50+
}),
51+
acceptor: {
52+
accept: async () => handler,
53+
},
54+
});
55+
}
56+
57+
function makeRSocketConnector() {
58+
return new RSocketConnector({
59+
transport: new TcpClientTransport({
60+
connectionOptions: {
61+
host: "127.0.0.1",
62+
port: 9090,
63+
},
64+
}),
65+
});
66+
}
67+
68+
function makeApolloServer({ typeDefs, resolvers }) {
69+
const server = new ApolloServer({
70+
typeDefs,
71+
resolvers,
72+
plugins: [
73+
{
74+
async serverWillStart() {
75+
let rSocketServer = makeRSocketServer({
76+
handler: server.getHandler(),
77+
});
78+
let closeable = await rSocketServer.bind();
79+
return {
80+
async drainServer() {
81+
closeable.close();
82+
},
83+
};
84+
},
85+
},
86+
],
87+
});
88+
return server;
89+
}
90+
91+
function makeApolloClient({ rsocketClient }) {
92+
return new ApolloClient({
93+
cache: new InMemoryCache(),
94+
link: makeRSocketLink({
95+
rsocket: rsocketClient,
96+
}),
97+
});
98+
}
99+
100+
async function sendMessage(
101+
client: ApolloClient<NormalizedCacheObject>,
102+
{ message }: { message: String }
103+
) {
104+
console.log("Sending message", { message });
105+
await client.mutate({
106+
variables: {
107+
message,
108+
},
109+
mutation: gql`
110+
mutation CreateMessage($message: String) {
111+
createMessage(message: $message) {
112+
message
113+
}
114+
}
115+
`,
116+
});
117+
}
118+
119+
function subcribe(
120+
client: ApolloClient<NormalizedCacheObject>,
121+
variables: Record<any, any>,
122+
query: DocumentNode
123+
) {
124+
return client.subscribe({
125+
variables,
126+
query,
127+
});
128+
}
129+
130+
async function main() {
131+
// server setup
132+
const typeDefs = readSchema();
133+
apolloServer = makeApolloServer({ typeDefs, resolvers });
134+
await apolloServer.start();
135+
136+
// client setup
137+
const connector = makeRSocketConnector();
138+
rsocketClient = await connector.connect();
139+
140+
const apolloClient = makeApolloClient({ rsocketClient });
141+
142+
console.log("\nSubscribing to messages.");
143+
let subscription = subcribe(
144+
apolloClient,
145+
{},
146+
gql`
147+
subscription ChannelMessages {
148+
messageCreated {
149+
message
150+
}
151+
}
152+
`
153+
).subscribe({
154+
next(data) {
155+
console.log("subscription event:", data);
156+
},
157+
error(err) {
158+
console.log(`subscription error: ${err}`);
159+
},
160+
complete() {},
161+
});
162+
163+
await sendMessage(apolloClient, {
164+
message: "my first message",
165+
});
166+
167+
await sendMessage(apolloClient, {
168+
message: "my second message",
169+
});
170+
171+
await sendMessage(apolloClient, {
172+
message: "my third message",
173+
});
174+
175+
subscription.unsubscribe();
176+
}
177+
178+
main()
179+
.catch((error: Error) => {
180+
console.error(error);
181+
exit(1);
182+
})
183+
.finally(async () => {
184+
await apolloServer.stop();
185+
rsocketClient.close();
186+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2021-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { PubSub } from "graphql-subscriptions";
17+
18+
const pubsub = new PubSub();
19+
20+
export const resolvers = {
21+
Query: {
22+
echo: (parent, args, context, info) => {
23+
const { message } = args;
24+
return {
25+
message,
26+
};
27+
},
28+
},
29+
Mutation: {
30+
createMessage: async (_, { message }, context, info) => {
31+
await pubsub.publish("POST_CREATED", {
32+
messageCreated: {
33+
message,
34+
},
35+
});
36+
},
37+
},
38+
Subscription: {
39+
messageCreated: {
40+
// subscribe must return an AsyncIterator
41+
// https://www.apollographql.com/docs/apollo-server/data/subscriptions/#resolving-a-subscription
42+
subscribe: () => pubsub.asyncIterator(["POST_CREATED"]),
43+
},
44+
},
45+
};
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Copyright 2021-2022 the original author or authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
"""
16+
17+
type ChatMessage {
18+
message: String
19+
}
20+
21+
type Query {
22+
echo(message: String): ChatMessage
23+
}
24+
25+
type Mutation {
26+
createMessage(message: String): ChatMessage
27+
}
28+
29+
type Subscription {
30+
messageCreated: ChatMessage
31+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2021-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { RSocket, RSocketConnector } from "rsocket-core";
18+
import { makeRSocketLink } from "rsocket-graphql-apollo-link";
19+
import { WebsocketClientTransport } from "rsocket-websocket-client";
20+
import { ApolloClient, InMemoryCache } from "@apollo/client/core";
21+
import gql from "graphql-tag";
22+
import WebSocket from "ws";
23+
import { exit } from "process";
24+
import { WellKnownMimeType } from "rsocket-composite-metadata";
25+
26+
let rsocketClient: RSocket;
27+
28+
function makeRSocketConnector() {
29+
return new RSocketConnector({
30+
setup: {
31+
dataMimeType: WellKnownMimeType.APPLICATION_JSON.toString(),
32+
metadataMimeType:
33+
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.toString(),
34+
},
35+
transport: new WebsocketClientTransport({
36+
url: "ws://localhost:7000/rsocket",
37+
wsCreator: (url) => new WebSocket(url) as any,
38+
}),
39+
});
40+
}
41+
42+
function makeApolloClient({ rsocketClient }) {
43+
return new ApolloClient({
44+
cache: new InMemoryCache(),
45+
link: makeRSocketLink({
46+
rsocket: rsocketClient,
47+
route: "graphql",
48+
}),
49+
});
50+
}
51+
52+
async function main() {
53+
// client setup
54+
const connector = makeRSocketConnector();
55+
rsocketClient = await connector.connect();
56+
57+
const apolloClient = makeApolloClient({ rsocketClient });
58+
59+
const greeting = await apolloClient.query({
60+
variables: {},
61+
query: gql`
62+
query greeting {
63+
greeting
64+
}
65+
`,
66+
});
67+
68+
console.log(greeting);
69+
70+
const echo = await apolloClient.query({
71+
variables: {
72+
input: "Hello World",
73+
},
74+
query: gql`
75+
query echo($input: String) {
76+
echo(input: $input) {
77+
message
78+
}
79+
}
80+
`,
81+
});
82+
83+
console.log(echo);
84+
}
85+
86+
main()
87+
.catch((error: Error) => {
88+
console.error(error);
89+
exit(1);
90+
})
91+
.finally(async () => {
92+
rsocketClient.close();
93+
});

packages/rsocket-examples/tsconfig.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33

44
"compilerOptions": {
55
"downlevelIteration": true,
6+
"sourceMap": true,
7+
"target": "ESNext"
68
}
79
}

0 commit comments

Comments
 (0)