14.07.2024
Сервис комментариев общается с фронтендом и основным приложением через HTTP API. Основные компоненты:
Определил следующие конечные точки:
GET /comments?postId={postId}
— получить список комментариев.POST /comments
— создать новый комментарий.DELETE /comments/{id}
— удалить комментарий.type Comment struct {
ID int64 `json:"id"`
PostID int64 `json:"postId"`
Author string `json:"author"`
Body string `json:"body"`
CreatedAt time.Time `json:"createdAt"`
}
Использовал фреймворк Gin
для простого роутинга и sqlx
для работы с базой.
package main
import (
"github.com/gin-gonic/gin"
"log"
)
func main() {
router := gin.Default()
db, err := NewDB("postgres://user:pass@db:5432/comments?sslmode=disable")
if err != nil {
log.Fatalf("DB connection failed: %v", err)
}
service := NewCommentService(db)
router.GET("/comments", service.GetComments)
router.POST("/comments", service.CreateComment)
router.DELETE("/comments/:id", service.DeleteComment)
log.Println("Comment service is running on :8080")
router.Run(":8080")
}
package main
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
)
func (s *CommentService) GetComments(c *gin.Context) {
postIdStr := c.Query("postId")
postId, err := strconv.ParseInt(postIdStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid postId"})
return
}
comments, err := s.repo.FindByPostID(postId)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, comments)
}
func (s *CommentService) CreateComment(c *gin.Context) {
var newComment Comment
if err := c.ShouldBindJSON(&newComment); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
created, err := s.repo.Create(newComment)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusCreated, created)
}
func (s *CommentService) DeleteComment(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid id"})
return
}
if err := s.repo.Delete(id); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.Status(http.StatusNoContent)
}
Использовал sqlx
и файл миграции schema.sql
:
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
post_id BIGINT NOT NULL,
author TEXT NOT NULL,
body TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT now()
);
В Symfony заменил старый сервис комментариев HTTP-клиентом на Go-сервис:
// src/Service/CommentClient.php
namespace App\Service;
use Symfony\Contracts\HttpClient\HttpClientInterface;
class CommentClient
{
private HttpClientInterface $httpClient;
private string $baseUri;
public function __construct(HttpClientInterface $httpClient, string $baseUri)
{
$this->httpClient = $httpClient;
$this->baseUri = rtrim($baseUri, '/');
}
public function getComments(int $postId): array
{
$response = $this->httpClient->request('GET', $this->baseUri . '/comments', [
'query' => ['postId' => $postId]
]);
return $response->toArray();
}
}
version: '3.8'
services:
blog:
build: ./symfony
ports:
- "8000:8000"
depends_on:
- comment-service
comment-service:
build: ./comment-service
ports:
- "8080:8080"
depends_on:
- db
db:
image: postgres:14
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: comments
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Написал простые тесты для Go через httptest
, проверил CRUD операции. Деплой организовал через Kubernetes с Helm-чартами: два Deployment (Symfony и Go), один StatefulSet (Postgres) и Service тип LoadBalancer.
Категории: Golang