Skip to content

Commit

Permalink
feat: apollo graphl link and server
Browse files Browse the repository at this point in the history
Signed-off-by: Kevin Viglucci <[email protected]>
  • Loading branch information
viglucci committed May 8, 2022
1 parent 7b1fe16 commit 4748c68
Show file tree
Hide file tree
Showing 26 changed files with 1,817 additions and 16 deletions.
2 changes: 1 addition & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ How to publish new releases for this project.

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.

ex: `@rsocket/[email protected]`
ex: `rsocket-[email protected]`

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

Expand Down
7 changes: 6 additions & 1 deletion packages/rsocket-examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@
"start-client-server-request-response-tcp": "ts-node -r tsconfig-paths/register src/ClientServerRequestResponseExampleTcp.ts",
"start-client-server-request-response-websocket": "ts-node -r tsconfig-paths/register src/ClientServerRequestResponseExampleWebSocket.ts",
"start-client-server-composite-metadata-route": "ts-node -r tsconfig-paths/register src/ClientServerCompositeMetadataRouteExample.ts",
"start-client-server-rx-composite-metadata-route": "ts-node -r tsconfig-paths/register src/rxjs/ClientServerCompositeMetadataRouteExample.ts"
"start-client-server-rx-composite-metadata-route": "ts-node -r tsconfig-paths/register src/rxjs/ClientServerCompositeMetadataRouteExample.ts",
"start-client-apollo-graphql": "ts-node -r tsconfig-paths/register src/graphql/apollo/client/example.ts",
"start-client-server-apollo-graphql": "ts-node -r tsconfig-paths/register src/graphql/apollo/client-server/example.ts"
},
"dependencies": {
"@apollo/client": "^3.5.10",
"rsocket-adapter-rxjs": "^1.0.0-alpha.1",
"rsocket-composite-metadata": "^1.0.0-alpha.1",
"rsocket-core": "^1.0.0-alpha.1",
"rsocket-tcp-client": "^1.0.0-alpha.1",
"rsocket-tcp-server": "^1.0.0-alpha.1",
"rsocket-websocket-client": "^1.0.0-alpha.1",
"rsocket-websocket-server": "^1.0.0-alpha.1",
"graphql-tag": "^2.12.6",
"graphql-subscriptions": "^2.0.0",
"ws": "~8.2.3"
},
"devDependencies": {
Expand Down
186 changes: 186 additions & 0 deletions packages/rsocket-examples/src/graphql/apollo/client-server/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright 2021-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { RSocket, RSocketConnector, RSocketServer } from "rsocket-core";
import { TcpClientTransport } from "rsocket-tcp-client";
import { TcpServerTransport } from "rsocket-tcp-server";
import { exit } from "process";
import { makeRSocketLink } from "rsocket-graphql-apollo-link";
import { ApolloServer } from "rsocket-graphql-apollo-server";
import {
ApolloClient,
InMemoryCache,
NormalizedCacheObject,
} from "@apollo/client/core";
import gql from "graphql-tag";
import { resolvers } from "./resolvers";
import { DocumentNode } from "@apollo/client";
import * as fs from "fs";
import path from "path";

let apolloServer: ApolloServer;
let rsocketClient: RSocket;

function readSchema() {
return fs.readFileSync(path.join(__dirname, "schema.graphql"), {
encoding: "utf8",
});
}

function makeRSocketServer({ handler }) {
return new RSocketServer({
transport: new TcpServerTransport({
listenOptions: {
port: 9090,
host: "127.0.0.1",
},
}),
acceptor: {
accept: async () => handler,
},
});
}

function makeRSocketConnector() {
return new RSocketConnector({
transport: new TcpClientTransport({
connectionOptions: {
host: "127.0.0.1",
port: 9090,
},
}),
});
}

function makeApolloServer({ typeDefs, resolvers }) {
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
{
async serverWillStart() {
let rSocketServer = makeRSocketServer({
handler: server.getHandler(),
});
let closeable = await rSocketServer.bind();
return {
async drainServer() {
closeable.close();
},
};
},
},
],
});
return server;
}

function makeApolloClient({ rsocketClient }) {
return new ApolloClient({
cache: new InMemoryCache(),
link: makeRSocketLink({
rsocket: rsocketClient,
}),
});
}

async function sendMessage(
client: ApolloClient<NormalizedCacheObject>,
{ message }: { message: String }
) {
console.log("Sending message", { message });
await client.mutate({
variables: {
message,
},
mutation: gql`
mutation CreateMessage($message: String) {
createMessage(message: $message) {
message
}
}
`,
});
}

function subcribe(
client: ApolloClient<NormalizedCacheObject>,
variables: Record<any, any>,
query: DocumentNode
) {
return client.subscribe({
variables,
query,
});
}

async function main() {
// server setup
const typeDefs = readSchema();
apolloServer = makeApolloServer({ typeDefs, resolvers });
await apolloServer.start();

// client setup
const connector = makeRSocketConnector();
rsocketClient = await connector.connect();

const apolloClient = makeApolloClient({ rsocketClient });

console.log("\nSubscribing to messages.");
let subscription = subcribe(
apolloClient,
{},
gql`
subscription ChannelMessages {
messageCreated {
message
}
}
`
).subscribe({
next(data) {
console.log("subscription event:", data);
},
error(err) {
console.log(`subscription error: ${err}`);
},
complete() {},
});

await sendMessage(apolloClient, {
message: "my first message",
});

await sendMessage(apolloClient, {
message: "my second message",
});

await sendMessage(apolloClient, {
message: "my third message",
});

subscription.unsubscribe();
}

main()
.catch((error: Error) => {
console.error(error);
exit(1);
})
.finally(async () => {
await apolloServer.stop();
rsocketClient.close();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2021-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PubSub } from "graphql-subscriptions";

const pubsub = new PubSub();

export const resolvers = {
Query: {
echo: (parent, args, context, info) => {
const { message } = args;
return {
message,
};
},
},
Mutation: {
createMessage: async (_, { message }, context, info) => {
await pubsub.publish("POST_CREATED", {
messageCreated: {
message,
},
});
},
},
Subscription: {
messageCreated: {
// subscribe must return an AsyncIterator
// https://www.apollographql.com/docs/apollo-server/data/subscriptions/#resolving-a-subscription
subscribe: () => pubsub.asyncIterator(["POST_CREATED"]),
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Copyright 2021-2022 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

type ChatMessage {
message: String
}

type Query {
echo(message: String): ChatMessage
}

type Mutation {
createMessage(message: String): ChatMessage
}

type Subscription {
messageCreated: ChatMessage
}
93 changes: 93 additions & 0 deletions packages/rsocket-examples/src/graphql/apollo/client/example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2021-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { RSocket, RSocketConnector } from "rsocket-core";
import { makeRSocketLink } from "rsocket-graphql-apollo-link";
import { WebsocketClientTransport } from "rsocket-websocket-client";
import { ApolloClient, InMemoryCache } from "@apollo/client/core";
import gql from "graphql-tag";
import WebSocket from "ws";
import { exit } from "process";
import { WellKnownMimeType } from "rsocket-composite-metadata";

let rsocketClient: RSocket;

function makeRSocketConnector() {
return new RSocketConnector({
setup: {
dataMimeType: WellKnownMimeType.APPLICATION_JSON.toString(),
metadataMimeType:
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.toString(),
},
transport: new WebsocketClientTransport({
url: "ws://localhost:7000/rsocket",
wsCreator: (url) => new WebSocket(url) as any,
}),
});
}

function makeApolloClient({ rsocketClient }) {
return new ApolloClient({
cache: new InMemoryCache(),
link: makeRSocketLink({
rsocket: rsocketClient,
route: "graphql",
}),
});
}

async function main() {
// client setup
const connector = makeRSocketConnector();
rsocketClient = await connector.connect();

const apolloClient = makeApolloClient({ rsocketClient });

const greeting = await apolloClient.query({
variables: {},
query: gql`
query greeting {
greeting
}
`,
});

console.log(greeting);

const echo = await apolloClient.query({
variables: {
input: "Hello World",
},
query: gql`
query echo($input: String) {
echo(input: $input) {
message
}
}
`,
});

console.log(echo);
}

main()
.catch((error: Error) => {
console.error(error);
exit(1);
})
.finally(async () => {
rsocketClient.close();
});
2 changes: 2 additions & 0 deletions packages/rsocket-examples/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@

"compilerOptions": {
"downlevelIteration": true,
"sourceMap": true,
"target": "ESNext"
}
}
Loading

0 comments on commit 4748c68

Please sign in to comment.