feat(api-gateway): retire teacher/student/parent-bff, route GraphQL to apollo-router
v2.1 M9+M10: BFF layer and old portals retired.
- api-gateway: remove TeacherBffURL/StudentBffURL/ParentBffURL config
- api-gateway: add ApolloRouterURL config and /api/graphql route
- api-gateway: /api/admin/graphql now proxies to apollo-router
- api-gateway: health checks now ping apollo-router instead of BFF
- deploy.yml: replace teacher-bff service block with apollo-router
- deploy.yml: add config-service service block (M3 dependency)
- deploy.yml: remove teacher-portal and admin-portal service blocks
- source code in services/{teacher,student,parent}-bff/ and apps/*-portal/ retained for rollback
This commit is contained in:
@@ -79,15 +79,9 @@ func main() {
|
||||
registerProxy(api, "classes", cfg.CoreEduServiceURL)
|
||||
// iam 服务路由(身份与访问管理)
|
||||
registerProxy(api, "iam", cfg.IamServiceURL)
|
||||
// teacher-bff 路由(教师聚合层 GraphQL)
|
||||
// BFF 在 /graphql 提供服务(@Controller("graphql")),需剥离 /api/v1/teacher 前缀
|
||||
// 契约 student-portal_contract.md §2.3:/api/v1/{bff}/* → {bff}:port/*
|
||||
registerBffProxy(api, "teacher", cfg.TeacherBffURL)
|
||||
// student-bff 路由(学生聚合层 GraphQL,P3)
|
||||
registerBffProxy(api, "student", cfg.StudentBffURL)
|
||||
// parent-bff 路由(家长聚合层 GraphQL,P4)
|
||||
// parent-bff 在 /v1/graphql 提供服务(ARB-022 §24.4 ISSUE-003 方案 A)
|
||||
registerBffProxy(api, "parent", cfg.ParentBffURL)
|
||||
// v2.1 M9:teacher-bff / student-bff / parent-bff 已下线,
|
||||
// 前端 GraphQL 查询统一通过 apollo-router 聚邦层。
|
||||
// /api/v1/teacher/* /api/v1/student/* /api/v1/parent/* 路由已移除。
|
||||
// core-edu 域路由(考试/作业/成绩)—— 下游 controller 在 /v1/{domain}/*,仅需剥离 /api
|
||||
registerProxy(api, "exams", cfg.CoreEduServiceURL)
|
||||
registerProxy(api, "homework", cfg.CoreEduServiceURL)
|
||||
@@ -110,25 +104,43 @@ func main() {
|
||||
registerProxy(api, "dashboard", cfg.DataAnaServiceURL)
|
||||
}
|
||||
|
||||
// admin 路由组:admin-portal 入口(契约 admin-portal_contract.md §2.3)
|
||||
// POST /api/admin/graphql → teacher-bff:3003/graphql(admin 命名空间)
|
||||
// 中间件链:熔断 → JWT 鉴权 → admin 角色强制 → 指标 → 反向代理
|
||||
// v2.1 M9:GraphQL 联邦入口(替代旧 BFF 聚合层)
|
||||
// /api/graphql → apollo-router:3000/graphql(统一前端 GraphQL 入口)
|
||||
// /api/admin/graphql → apollo-router:3000/graphql(admin 命名空间)
|
||||
// 中间件链:熔断 → JWT 鉴权 → 指标 → 反向代理(admin 路由额外强制 admin 角色)
|
||||
graphqlGroup := r.Group("/api/graphql")
|
||||
graphqlGroup.Use(middleware.CircuitBreaker("apollo-router"))
|
||||
graphqlGroup.Use(middleware.AuthMiddleware(cfg, fetcher))
|
||||
graphqlGroup.Use(observability.Metrics())
|
||||
{
|
||||
// 路径重写:/api/graphql → /graphql(apollo-router supergraph.path)
|
||||
graphqlProxy, err := proxy.NewProxyRewrite(cfg.ApolloRouterURL, func(p string) string {
|
||||
return strings.TrimPrefix(p, "/api/graphql")
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to create apollo-router graphql proxy", "target", cfg.ApolloRouterURL, "error", err)
|
||||
panic(err)
|
||||
}
|
||||
graphqlGroup.Any("", proxy.ProxyHandler(graphqlProxy))
|
||||
graphqlGroup.Any("/", proxy.ProxyHandler(graphqlProxy))
|
||||
}
|
||||
|
||||
// admin GraphQL 入口(admin-portal 仍走独立路径以强制 admin 角色)
|
||||
admin := r.Group("/api/admin")
|
||||
admin.Use(middleware.CircuitBreaker("teacher-bff-admin"))
|
||||
admin.Use(middleware.CircuitBreaker("apollo-router-admin"))
|
||||
admin.Use(middleware.AuthMiddleware(cfg, fetcher))
|
||||
admin.Use(middleware.AdminRoleMiddleware())
|
||||
admin.Use(observability.Metrics())
|
||||
{
|
||||
// /api/admin/graphql 是唯一入口(契约 §2.3 要求),
|
||||
// 路径重写:/api/admin/graphql → /graphql(teacher-bff @Controller("graphql"))
|
||||
graphqlProxy, err := proxy.NewProxyRewrite(cfg.TeacherBffURL, func(p string) string {
|
||||
// 路径重写:/api/admin/graphql → /graphql(apollo-router)
|
||||
adminGraphqlProxy, err := proxy.NewProxyRewrite(cfg.ApolloRouterURL, func(p string) string {
|
||||
return strings.TrimPrefix(p, "/api/admin")
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to create admin graphql proxy", "target", cfg.TeacherBffURL, "error", err)
|
||||
slog.Error("failed to create admin graphql proxy", "target", cfg.ApolloRouterURL, "error", err)
|
||||
panic(err)
|
||||
}
|
||||
admin.Any("/graphql", proxy.ProxyHandler(graphqlProxy))
|
||||
admin.Any("/graphql", proxy.ProxyHandler(adminGraphqlProxy))
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
@@ -180,22 +192,5 @@ func registerProxy(api *gin.RouterGroup, prefix, targetURL string) {
|
||||
api.Any("/"+prefix+"/*path", handler)
|
||||
}
|
||||
|
||||
// registerBffProxy 创建带路径重写的反向代理,用于 BFF 路由(teacher/student/parent)。
|
||||
// BFF 在 /graphql 或 /v1/graphql 提供服务(@Controller),与下游 controller 在 /v1/{domain}/* 的
|
||||
// 非 BFF 服务不同,需剥离 /api/v1/{prefix} 前缀,仅转发剩余路径到下游。
|
||||
// 例:/api/v1/teacher/graphql → /graphql(teacher-bff:3003/graphql)。
|
||||
// 例:/api/v1/parent/v1/graphql → /v1/graphql(parent-bff:3010/v1/graphql,ARB-022 §24.4 ISSUE-003 方案 A)。
|
||||
// 契约依据:student-portal_contract.md §2.3 /api/v1/{bff}/* → {bff}:port/*
|
||||
func registerBffProxy(api *gin.RouterGroup, prefix, targetURL string) {
|
||||
stripPrefix := "/api/v1/" + prefix
|
||||
p, err := proxy.NewProxyRewrite(targetURL, func(p string) string {
|
||||
return strings.TrimPrefix(p, stripPrefix)
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to create bff proxy", "prefix", prefix, "target", targetURL, "error", err)
|
||||
panic(err)
|
||||
}
|
||||
handler := proxy.ProxyHandler(p)
|
||||
api.Any("/"+prefix, handler)
|
||||
api.Any("/"+prefix+"/*path", handler)
|
||||
}
|
||||
// registerBffProxy 已在 v2.1 M9 移除:teacher-bff / student-bff / parent-bff 由 apollo-router 替代。
|
||||
// 前端 GraphQL 查询统一通过 /api/graphql → apollo-router:3000/graphql。
|
||||
|
||||
Reference in New Issue
Block a user