Appendix A: GraphQL schema and customization options - Real-Time Live Sports Updates Using AWS AppSync

Appendix A: GraphQL schema and customization options

This solution is based on the AWS AppSync GraphQL API. The GraphQL API is defined by a GraphQL schema file. This section provides information about how the schema is designed, which GraphQL types and operations are exposed by the API, and the purpose of each of type and operation.

The solution’s GraphQL schema is designed to provide a general approach to deliver sports data. The schema is based on games (or matches) with home and away competitors, so it’s suitable for delivering real-time sports updates when two competitors (teams or single players) are playing (for example, soccer, football, basketball, volleyball, hockey, baseball, and tennis).

You can customize the GraphQL schema file and redeploy the API stack to address different use cases (for example, real-time live coverage of events not related to sports).

This solution provides several types that define different concepts based on the set up of your data providers. These types can be accessed by both @aws_iam and @aws_api_key authentication methods, but additional authorization rules are implemented for specific fields or operations.

The Sports type defines the concept of a sport (soccer, football, etc.). This type lets you to define a FeedConfig and a list of competitions.

The following code sample is a Sport type schema.

type Sport @aws_iam @aws_api_key { id: ID! name: String! competitions(filter: ModelCompetitionFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelCompetitionConnection createdAt: AWSDateTime! updatedAt: AWSDateTime! feedConfig: FeedConfig @aws_iam }

The Competition type defines the concept of a competition or a tournament for a specific sport. It sets up FeedConfig, provides a reference to the related sport, and provides a list of seasons so you can map different seasons for a specific tournament (for example, a 2019/2020 season for a soccer tournament or a 2020 regular season for a football tournament).

The following code sample is a Competition type schema.

type Competition @aws_iam @aws_api_key { id: ID! name: String! type: String! sport: Sport sportId: ID! seasons(year: ModelStringKeyConditionInput, filter: ModelSeasonFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelSeasonConnection country: String countryCode: String createdAt: AWSDateTime! updatedAt: AWSDateTime! feedConfig: FeedConfig @aws_iam }

The following code sample is a Season type schema.

type Season @aws_iam @aws_api_key { id: ID! name: String! year: String! competition: Competition competitionId: ID! startDate: AWSDate! endDate: AWSDate! status: Status! stages(name: ModelStringKeyConditionInput, filter: ModelStageFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelStageConnection createdAt: AWSDateTime! updatedAt: AWSDateTime! feedConfig: FeedConfig @aws_iam }

Each Season type has a list of stages and a status. The Stage type identifies the time parameters for a tournament season (for example, week 1, week 2, playoff round 1, semifinals, etc). You must set up the FeedConfig to manage different data providers and different feed types for the different Stage types (companies in the Media and Entertainment industry may use different data providers or feeds based on the Stage type).

The following code sample is a Stage type schema.

type Stage @aws_iam @aws_api_key { id: ID! startDate: AWSDate! endDate: AWSDate! name: String! sequence: Int season: Season seasonId: ID! games(filter: ModelGameFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelGameConnection createdAt: AWSDateTime! updatedAt: AWSDateTime! feedConfig: FeedConfig @aws_iam }

The Game type identifies the concept of a game. You can specify game parameters including venue, competitors, scoring drives, and stats. Stats is a field of type AWSJSON, which enables you to enter JSON-based statistical information for a game. For information about AWSJSON, AWSDateTime, and other AWS defined scalar types, refer to Scalar Types in AWS AppSync in the AWS AppSync Developer Guide.

When creating a game with a FeedConfig that specifies a URL, the plannedKickoffTime field sets up the start time for polling AWS Step Function workflow. The IngestionPollerFunction AWS Lambda function runs the workflow based on the CloudWatchRule expression (an input parameter in the AWS Cloudformation template).

type Game @aws_iam @aws_api_key { id: ID! stage: Stage stageId: ID! plannedKickoffTime: AWSDateTime! venue: Venue home: Competitor away: Competitor gameStatus: GameStatus scoringDrives: [ScoringDrive] events(createdAt: ModelStringKeyConditionInput, filter: ModelGameEventFilterInput, sortDirection: ModelSortDirection, limit: Int, nextToken: String): ModelGameEventConnection stats: AWSJSON createdAt: AWSDateTime! updatedAt: AWSDateTime! feedConfig: FeedConfig @aws_iam }

The GameStatus type contains information about the current game’s scores, the winning team or player, and aggregate scores (for events containing multiple rounds or sporting events with a best-of series in a playoff round).

type GameStatus @aws_iam @aws_api_key { status: Status! clock: String clockStoppageAnnounced: String clockStoppagePlayer: String winner: Competitor aggregateAwayScore: Int aggregateHomeScore: Int aggregateWinner: Competitor awayNormaltimeScore: Int awayOvertimeScore: Int awayScore: Int homeNormaltimeScore: Int homeOvertimeScore: Int homeScore: Int possession: String location: String play: String sections: [GameSection] }

The GameSection type provides scores and stats for specific parts of a game (for example, quarter, inning, half, set, etc).

type GameSection @aws_iam @aws_api_key { awayScore: Int homeScore: Int sequence: Int! name: String! type: String stats: AWSJSON }

The GameEvent type manages real-time live updates for every event occurring in a game (for example, changes in the score, substitutions, play-by-play coverage, big plays, change of possessions, etc).

type GameEvent @aws_iam @aws_api_key { id: ID! game: Game gameId: ID! type: String clock: String section: GameSection competitor: Competitor homeScore: Int awayScore: Int scorer: Player assist: Player playerIn: Player playerOut: Player commentary: String players: [Player] createdAt: AWSDateTime! updatedAt: AWSDateTime! }

In GraphQL operations, all mutations are allowed only when using @aws_iam authentication type. To invoke these mutations, you need an appropriate AWS Identity and Access Management (IAM) role and policies, such as the execution roles created by this solution for AWS Lambda functions.

The following code sample lists of all mutations provided as default by the solution.

type Mutation { createSport(input: CreateSportInput!, condition: ModelSportConditionInput): Sport @aws_iam updateSport(input: UpdateSportInput!, condition: ModelSportConditionInput): Sport @aws_iam deleteSport(input: DeleteSportInput!, condition: ModelSportConditionInput): Sport @aws_iam createSeason(input: CreateSeasonInput!, condition: ModelSeasonConditionInput): Season @aws_iam updateSeason(input: UpdateSeasonInput!, condition: ModelSeasonConditionInput): Season @aws_iam deleteSeason(input: DeleteSeasonInput!, condition: ModelSeasonConditionInput): Season @aws_iam createCompetition(input: CreateCompetitionInput!, condition: ModelCompetitionConditionInput): Competition @aws_iam updateCompetition(input: UpdateCompetitionInput!, condition: ModelCompetitionConditionInput): Competition @aws_iam deleteCompetition(input: DeleteCompetitionInput!, condition: ModelCompetitionConditionInput): Competition @aws_iam createStage(input: CreateStageInput!, condition: ModelStageConditionInput): Stage @aws_iam updateStage(input: UpdateStageInput!, condition: ModelStageConditionInput): Stage @aws_iam deleteStage(input: DeleteStageInput!, condition: ModelStageConditionInput): Stage @aws_iam createGame(input: CreateGameInput!, condition: ModelGameConditionInput): Game @aws_iam updateGame(input: UpdateGameInput!, condition: ModelGameConditionInput): Game @aws_iam deleteGame(input: DeleteGameInput!, condition: ModelGameConditionInput): Game @aws_iam createGameEvent(input: CreateGameEventInput!, condition: ModelGameEventConditionInput): GameEvent @aws_iam updateGameEvent(input: UpdateGameEventInput!, condition: ModelGameEventConditionInput): GameEvent @aws_iam deleteGameEvent(input: DeleteGameEventInput!, condition: ModelGameEventConditionInput): GameEvent @aws_iam }

Queries can be invoked by both @aws_iam and @api_key security types. Subscriptions can only be invoked by @aws_iam, except for subscriptions related to the GameEvent type, which are open by default. You can customize this behavior by modifying the following section of the schema (add or remove authorization GraphQL directives).

type Subscription { onCreateSport: Sport @aws_subscribe(mutations: ["createSport"]) @aws_iam onUpdateSport: Sport @aws_subscribe(mutations: ["updateSport"]) @aws_iam onDeleteSport: Sport @aws_subscribe(mutations: ["deleteSport"]) @aws_iam onCreateSeason: Season @aws_subscribe(mutations: ["createSeason"]) @aws_iam onUpdateSeason: Season @aws_subscribe(mutations: ["updateSeason"]) @aws_iam onDeleteSeason: Season @aws_subscribe(mutations: ["deleteSeason"]) @aws_iam onCreateCompetition: Competition @aws_subscribe(mutations: ["createCompetition"]) @aws_iam onUpdateCompetition: Competition @aws_subscribe(mutations: ["updateCompetition"]) @aws_iam onDeleteCompetition: Competition @aws_subscribe(mutations: ["deleteCompetition"]) @aws_iam onCreateStage: Stage @aws_subscribe(mutations: ["createStage"]) @aws_iam onUpdateStage: Stage @aws_subscribe(mutations: ["updateStage"]) @aws_iam onDeleteStage: Stage @aws_subscribe(mutations: ["deleteStage"]) @aws_iam onCreateGame: Game @aws_subscribe(mutations: ["createGame"]) @aws_iam onUpdateGame: Game @aws_subscribe(mutations: ["updateGame"]) @aws_iam onDeleteGame: Game @aws_subscribe(mutations: ["deleteGame"]) @aws_iam onCreateGameEvent(gameId:ID): GameEvent @aws_subscribe(mutations: ["createGameEvent"]) onUpdateGameEvent: GameEvent @aws_subscribe(mutations: ["updateGameEvent"]) onDeleteGameEvent: GameEvent @aws_subscribe(mutations: ["deleteGameEvent"]) }