#Amplify project with GraphQL API needs an additional REST API with Sockets (API Gateway)

1 messages · Page 1 of 1 (latest)

real oyster
#

Our project is very happily and productively using the Amplify GraphQL API category. We're making good use of subscriptions - and even server-side filtered subscriptions.

We have a use-case for our application that requires we build out some primitive chat and notification features, in-app.

Using server-side filtered GraphQL subscriptions, we're running into scalability problems (exceeding max socket connection limits).

We're thinking of tackling this by adding a serverless API Gateway of type "WebSocket API" --> The AWS Console supports 4 types: HTTP API, WebSocket API, REST API, and REST API Private.

Is there a recommended solutions pattern for this?

Should I try to hack my way around the AWS CLI and its cloudformation output?

Is there a way to use amplify override api to achieve this?

Or should I go down the path of doing this using a Custom CDK resource?

For inspiration, we were looking at something like:
https://github.com/aws-samples/simple-websockets-chat-app

cc: @worldly furnace (in case you might already know 😎 )

GitHub

This SAM application provides the Lambda functions, DynamoDB table, and roles to allow you to build a simple chat application based on API Gateway's new WebSocket-based API feature. - GitH...

worldly furnace
#

👋 I do not know off the top of my head but I'm interested in the use case! What motivated you to move the filtered subscriptions server-side?

real oyster
#

It starts to get heavy on the client-side when, for example, implementing a chat application.

For each DM between any two users --> that's technically a "chat room" or "topic"

Let's say you have a user with 50 DMs in their inbox...are you supposed to create 50 different subscription objects for each of the "rooms" a user is in?

#

The best attempt we made at a backend for a chat use-case looks like this:

type Room @model @searchable @auth(rules: [{ allow: public }]) {
  id: ID!
  name: String
  type: ChatRoomType @default(value: "GROUP")
  users: [RoomUser] @hasMany(indexName: "byRoom", fields: ["id"])
  messages: [Message] @hasMany(indexName: "byRoom", fields: ["id"])
  group: Group @belongsTo(fields: ["groupId"])
  groupId: ID @index(name: "byGroup")
  project: Project @belongsTo(fields: ["projectId"])
  projectId: ID @index(name: "byProject")
  files: [FileAttachment] @hasMany(indexName: "byRoom", fields: ["id"])
}

type RoomUser @model @searchable @auth(rules: [{ allow: public }]) {
  id: ID! @primaryKey(sortKeyFields: ["userId", "roomId"])
  user: User @belongsTo(fields: ["userId"])
  userId: ID! @index(name: "byUser")
  room: Room @belongsTo(fields: ["roomId"])
  roomId: ID! @index(name: "byRoom")
  isTyping: Boolean
}

type Message @model @searchable @auth(rules: [{ allow: public }]) {
  id: ID! @primaryKey(sortKeyFields: ["roomId"])
  content: String!
  roomId: ID! @index(name: "byRoom")
  userId: ID! @index(name: "byUser")
  authoredBy: User! @hasOne(fields: ["userId"])
  createdAt: AWSDateTime!
  updatedAt: AWSDateTime!
  readReceipts: [ReadReceipt] @hasMany(indexName: "byMessage", fields: ["id"])
  attachments: [FileAttachment] @hasMany(indexName: "byMessage", fields: ["id"])
}