Skip to content

Commit

Permalink
Merge pull request #134 from ColeWalker/feature/create-points-pubsub
Browse files Browse the repository at this point in the history
feat: ⚗️ add experimental feature for redemption reward pubsubs
  • Loading branch information
ColeWalker authored Oct 3, 2020
2 parents 519d3ba + 1142444 commit 8041df9
Show file tree
Hide file tree
Showing 10 changed files with 1,001 additions and 45 deletions.
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ By default it will run at `http://localhost:5555/graphql`.
- [StreamUserLink](#streamuserlink)
- [Game](#game)
- [GameStreamLink](#gamestreamlink)
- [PubSubs](#pubsubs)
- [RedemptionPubSub](#redemptionpubsub)
- [RedemptionUserLink](#redemptionuserlink)

## Environment Variables

Expand Down Expand Up @@ -144,6 +147,10 @@ Base schema, all other modules extend this.

### Subscriber

```ts
import { SubscriberModule } from 'twitch-graphql'
```

```graphql
extend type Query {
latestSub: Subscriber!
Expand All @@ -164,6 +171,10 @@ type Subscriber {

### User

```ts
import { UserModule } from 'twitch-graphql'
```

Please note that using follows with a high number of maxPages will likely result in rate limiting from twitch.

```graphql
Expand Down Expand Up @@ -204,6 +215,10 @@ extend type Query {

### UserSubscriberLink

```ts
import { UserSubscriberLinkModule } from 'twitch-graphql'
```

This module extends Subscriber to add the user field. Only use if both modules are being used in your application.

```graphql
Expand All @@ -222,6 +237,10 @@ extend type User {

### Stream

```ts
import { Stream } from 'twitch-graphql'
```

```graphql
type Stream {
language: String!
Expand Down Expand Up @@ -261,6 +280,10 @@ enum StreamType {

### StreamUserLink

```ts
import { StreamUserLinkModule } from 'twitch-graphql'
```

This module extends Stream to add the user field, and User to add the stream field. Only use if both modules are being used in your application.

```graphql
Expand All @@ -274,6 +297,10 @@ extend type Stream {

### Game

```ts
import { GameModule } from 'twitch-graphql'
```

```graphql
type Game {
boxArtUrl: String!
Expand All @@ -288,10 +315,62 @@ extend type Query {

### GameStreamLink

```ts
import { GameStreamLinkModule } from 'twitch-graphql'
```

This module extends Stream to add the game field. Only use if both modules are being used in your application.

```graphql
extend type Stream {
game: Game
}
```

## PubSubs

Twitch PubSubs are supported using [GraphQL Subscriptions.](https://www.apollographql.com/docs/apollo-server/data/subscriptions/)

Currently these PubSub modules are in an **experimental** phase, since no unit tests have been written for them, and have only been tested manually.

### RedemptionPubSub

```ts
import { RedemptionPubSubModule } from 'twitch-graphql'
```

```graphql
type Redemption {
userId: String
id: String
channelId: String
userName: String
userDisplayName: String
redemptionDate: String
rewardId: String
rewardName: String
rewardPrompt: String
rewardCost: Int
rewardIsQueued: String
rewardImage: String
message: String
status: String
}

extend type Subscription {
newRedemption: Redemption
}
```

### RedemptionUserLink

```**ts**
import { RedemptionUserLinkModule } from 'twitch-graphql'
```

```graphql
extend type Redemption {
user: User
channelRedeemedAt: User
}
```
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
"url": "https://github.com/ColeWalker/twitch-graphql-server.git"
},
"dependencies": {
"@types/callback-to-async-iterator": "^1.1.2",
"@types/node": "^14.0.27",
"axios": "^0.20.0",
"callback-to-async-iterator": "^1.1.1",
"dotenv": "^8.2.0",
"graphql": "^15.3.0",
"graphql-modules": "^1.0.0-alpha.1",
Expand All @@ -47,6 +49,7 @@
"twitch-webhooks": "^4.1.3"
},
"devDependencies": {
"apollo-server": "^2.18.1",
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@types/cors": "^2.8.7",
Expand Down
10 changes: 10 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,13 @@ export {
StreamUserLinkResolvers,
StreamUserLinkSchema,
} from './schema/stream-user-link-type-schema'
export {
RedemptionPubSubModule,
RedemptionPubSubResolvers,
RedemptionPubSubSchema,
} from './schema/redemption-pubsub-type-schema'
export {
RedemptionUserLinkModule,
RedemptionUserLinkResolvers,
RedemptionUserLinkSchema,
} from './schema/redemption-pubsub-user-link-type-schema'
14 changes: 14 additions & 0 deletions src/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ import {
StreamUserLinkModule,
StreamUserLinkResolvers,
StreamUserLinkSchema,
RedemptionPubSubModule,
RedemptionPubSubResolvers,
RedemptionPubSubSchema,
RedemptionUserLinkModule,
RedemptionUserLinkResolvers,
RedemptionUserLinkSchema,
} from './index'
import nock from 'nock'
import {
Expand Down Expand Up @@ -89,6 +95,12 @@ describe('npm package', () => {
expect(StreamUserLinkModule).toBeTruthy()
expect(StreamUserLinkResolvers).toBeTruthy()
expect(StreamUserLinkSchema).toBeTruthy()
expect(RedemptionUserLinkModule).toBeTruthy()
expect(RedemptionUserLinkResolvers).toBeTruthy()
expect(RedemptionUserLinkSchema).toBeTruthy()
expect(RedemptionPubSubModule).toBeTruthy()
expect(RedemptionPubSubResolvers).toBeTruthy()
expect(RedemptionPubSubSchema).toBeTruthy()
})

it('modules should work together', async () => {
Expand All @@ -102,6 +114,8 @@ describe('npm package', () => {
GameStreamLinkModule,
GameModule,
StreamUserLinkModule,
RedemptionPubSubModule,
RedemptionUserLinkModule,
],
})
const schema = app.createSchemaForApollo()
Expand Down
6 changes: 6 additions & 0 deletions src/schema/query-type-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export const QuerySchema = gql`
type Query {
_: Boolean
}
type Subscription {
_: Boolean
}
type Mutation {
_: Boolean
}
`

export const QueryModule = createModule({
Expand Down
64 changes: 64 additions & 0 deletions src/schema/redemption-pubsub-type-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { createModule, gql } from 'graphql-modules'
import { TwitchClients } from '../injections/Twitch-Clients'
import { TwitchId } from '../injections/Twitch-Id'
import { UserId } from '../injections/User-Id'
import asyncify from 'callback-to-async-iterator'

export const RedemptionPubSubResolvers = {
Subscription: {
newRedemption: {
subscribe: async (
_: any,
_args: any,
{ injector }: GraphQLModules.Context
) => {
const clients = injector.get(TwitchClients)

const twitchClient = await clients.apiClient()

const pubSubClient = await clients.pubSubClient()
await pubSubClient.registerUserListener(twitchClient)
const curriedOnRedemption = (cb: any) =>
pubSubClient.onRedemption('23573216', cb)

const asyncified = asyncify(curriedOnRedemption)

return asyncified
},
resolve: (redemption: any) => {
return redemption
},
},
},
}

export const RedemptionPubSubSchema = gql`
type Redemption {
userId: String
id: String
channelId: String
userName: String
userDisplayName: String
redemptionDate: String
rewardId: String
rewardName: String
rewardPrompt: String
rewardCost: Int
rewardIsQueued: String
rewardImage: String
message: String
status: String
}
extend type Subscription {
newRedemption: Redemption
}
`

export const RedemptionPubSubModule = createModule({
id: `redemption-pubsub-module`,
dirname: __dirname,
providers: [TwitchClients, TwitchId, UserId],
typeDefs: RedemptionPubSubSchema,
resolvers: RedemptionPubSubResolvers,
})
45 changes: 45 additions & 0 deletions src/schema/redemption-pubsub-user-link-type-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { createModule, gql } from 'graphql-modules'
import { PubSubRedemptionMessage } from 'twitch-pubsub-client/lib'
import { TwitchClients } from '../injections/Twitch-Clients'
import { TwitchId } from '../injections/Twitch-Id'
import { UserId } from '../injections/User-Id'

export const RedemptionUserLinkResolvers = {
Redemption: {
user: async (
redemption: PubSubRedemptionMessage,
_args: any,
{ injector }: GraphQLModules.Context
) => {
const clients = injector.get(TwitchClients)
const twitchClient = await clients.apiClient()

return twitchClient.helix.users.getUserById(redemption.userId)
},
channelRedeemedAt: async (
redemption: PubSubRedemptionMessage,
_args: any,
{ injector }: GraphQLModules.Context
) => {
const clients = injector.get(TwitchClients)
const twitchClient = await clients.apiClient()

return twitchClient.helix.users.getUserById(redemption.channelId)
},
},
}

export const RedemptionUserLinkSchema = gql`
extend type Redemption {
user: User
channelRedeemedAt: User
}
`

export const RedemptionUserLinkModule = createModule({
id: `redemption-pubsub-user-link-module`,
dirname: __dirname,
providers: [TwitchClients, TwitchId, UserId],
typeDefs: RedemptionUserLinkSchema,
resolvers: RedemptionUserLinkResolvers,
})
43 changes: 28 additions & 15 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import express from 'express'
import cors from 'cors'
import { graphqlHTTP } from 'express-graphql'
import http from 'http'
import { QueryModule } from './schema/query-type-schema'
import { SubscriberModule } from './schema/subscriber-type-schema'
import { UserModule } from './schema/user-type-schema'
Expand All @@ -9,7 +9,10 @@ import { GameModule } from './schema/game-type-schema'
import { createApplication } from 'graphql-modules'
import { UserSubscriberLinkModule } from './schema/user-subscriber-link-type-schema'
import { GameStreamLinkModule } from './schema/game-stream-link-type-schema'
import { RedemptionPubSubModule } from './schema/redemption-pubsub-type-schema'
import { StreamUserLinkModule } from './schema/stream-user-link-type-schema'
import { RedemptionUserLinkModule } from './schema/redemption-pubsub-user-link-type-schema'
import { ApolloServer } from 'apollo-server-express'
require('dotenv').config()

let port = 5555
Expand Down Expand Up @@ -51,21 +54,31 @@ const app = createApplication({
GameStreamLinkModule,
GameModule,
StreamUserLinkModule,
RedemptionPubSubModule,
RedemptionUserLinkModule,
],
})
const execute = app.createExecution()
const server = express()
server.use(cors())
server.use(
'/graphql',
graphqlHTTP((request: any) => ({
schema: app.schema,
graphiql: useGraphiql,
customExecuteFn: execute as any,
context: { request },
}))
)

server.listen(port, () => {
console.log(`server listening at ${port}, graphiql enabled: ${useGraphiql}`)
const schema = app.createSchemaForApollo()
const server = new ApolloServer({
schema,
introspection: useGraphiql,

subscriptions: `/subscriptions`,
playground: useGraphiql,
})
const expressApp = express()
expressApp.use(cors())

server.applyMiddleware({ app: expressApp })
const httpServer = http.createServer(expressApp)
server.installSubscriptionHandlers(httpServer)

httpServer.listen(port, () => {
console.log(
`🚀 Server ready at http://localhost:${port}${server.graphqlPath}`
)
console.log(
`🚀 Subscriptions ready at ws://localhost:${port}${server.subscriptionsPath}`
)
})
Loading

0 comments on commit 8041df9

Please sign in to comment.