_examples/mini-habr-with-subscriptions/README.md
This project demonstrates how to implement GraphQL subscriptions and cursor-based pagination using gqlgen in a mini API similar to Habr. The implementation follows the official GraphQL documentation specifications and showcases real-time data exchange and efficient data fetching patterns.
The project provides a complete implementation of GraphQL subscriptions using WebSockets, allowing clients to receive real-time updates when new comments are added to posts. This follows the GraphQL subscription specification and shows how to:
Following GraphQL's Relay Cursor Connections Specification, this project implements efficient cursor-based pagination for comments on posts. This approach:
This project implements an API for Ozon similar to Habr. It allows working with posts and comments using GraphQL. The system supports creating posts, adding comments, managing comment enabling/disabling for posts, as well as subscribing to new comment notifications.
Note on patterns: Unlike the classic Observer pattern, where observers directly register with the observed object, this project implements the Publish-Subscribe pattern, which introduces an intermediate layer (message broker) between publishers and subscribers. This provides a higher degree of decomposition: publishers don't know about specific subscribers, and subscribers don't know about publishers. Subscriptions are grouped by post identifier, which allows implementing event filtering at the broker level.
To launch the project, follow these steps:
Clone the repository
git clone https://github.com/nabishec/ozon_habr_api.git
cd ozon_habr_api
Launch in Docker containers
docker-compose up
Using the API
After launching, open your browser and go to:
http://localhost:8080
By default, the project uses PostgreSQL for data storage. If you want to use in-memory storage for testing, change the line in the Dockerfile:
RUN go build -o main ./cmd/main.go
and add the flag -s m:
RUN go build -o main ./cmd/main.go -s m
Interactive GraphQL playground console is available at:
query{
posts{
id
title
text
authorID
commentsEnabled
createDate
}
}
query {
post(postID: 1) {
id
title
text
comments(first: 5) {
edges {
node {
id
text
authorID
createDate
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
mutation {
addPost(postInput: {
authorID: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
title: "New post"
text: "Post content"
commentsEnabled: true
}) {
id
title
createDate
}
}
mutation {
addComment(commentInput: {
authorID: "123e4567-e89b-12d3-a456-426614174000",
postID: 1,
parentID: 1, # ID of existing comment
text: "This is a reply to comment 1"
}) {
id
text
parentID
}
}
subscription {
commentAdded(postID: 1) {
id
text
authorID
createDate
}
}
For testing the API, you can use any GraphQL clients, such as Insomnia, Postman, or GraphiQL.
ozon_habr_api/
├── cmd/
│ ├── db_connection/
│ │ ├── cache.go (Redis connection and configuration for caching)
│ │ └── database.go (PostgreSQL connection and configuration)
│ ├── server/
│ │ └── server.go (GraphQL server setup and launch)
│ └── main.go (Main entry point, application setup and launch)
├── graph/
│ ├── model/
│ │ └── models_gen.go (Automatically generated GraphQL models)
│ ├── generated.go (Generated GraphQL code (gqlgen))
│ ├── resolver.go (Main GraphQL resolvers)
│ ├── schema.graphqls (GraphQL schema definition)
│ ├── schema.resolvers.go (GraphQL resolvers implementation)
│ └── subscription.go (Implementation of structures and methods for subscription management)
├── internal/
│ ├── handlers/
│ │ ├── comment_mutation/ (Comment mutations logic handlers)
│ │ │ ├── interface.go (Interface for comment mutations)
│ │ │ └── mutations.go (Comment mutations implementation)
│ │ ├── comment_query/ (Comment queries logic handlers)
│ │ │ ├── interface.go (Interface for comment queries)
│ │ │ └── query.go (Comment queries implementation)
│ │ ├── post_mutation/ (Post mutations logic handlers)
│ │ │ ├── interface.go (Interface for post mutations)
│ │ │ └── mutations.go (Post mutations implementation)
│ │ └── post_query/ (Post queries logic handlers)
│ │ ├── interface.go (Interface for post queries)
│ │ └── query.go (Post queries implementation)
│ ├── pkg/
│ │ ├── cursor/
│ │ | └── cursor.go (Functions for working with cursors in pagination)
│ │ └── errs/
│ │ └── errors.go (Stores business logic errors)
│ ├── model/
│ │ └── model.go (Internal data models)
│ └── storage/
│ ├── db/ (Implementation of database storage)
│ │ └── resolvers.go (Implementation of methods for working with PostgreSQL database)
│ ├── in-memory/ (Implementation of in-memory data storage)
│ │ └── resolvers.go (Implementation of methods for working with in-memory data)
│ └── interface.go (Interface for data storage (PostgreSQL, in-memory))
├── migrations/
│ └── 001_create_tables.up.sql (SQL script for database migration (creating tables))
├── .env (Environment variables file (database settings, Redis, etc.))
├── .gitignore (List of ignored files and directories for Git)
├── docker-compose.yml (Docker Compose configuration for launching the application and dependencies)
├── Dockerfile (Instructions for building Docker image)
├── go.mod (Go dependencies file)
├── go.sum (Go dependencies checksums file)
├── gqlgen.yml (Configuration file for gqlgen)
├── LICENSE (Project license)
└── README.md (Project description file)