APIs (REST, GraphQL, gRPC, SOAP)
🧪 Experimental — parte da camada
core(kyrux/core), rotulada "experimental" pelo próprioUSE.mddo framework. API pode mudar entre versões sem aviso.
Os quatro protocolos vivem como adapters (core/adapters/...) sobre o
core.Core — um orquestrador novo, paralelo ao bootstrap tradicional, com
seu próprio ciclo de vida (Init → Configure → Start → Shutdown).
import "kyrux/core"
c := core.New()
// ... registra REST/GraphQL/gRPC/SOAP ...
c.Run() // Start em todos os módulos ativados
defer c.Shutdown() // Shutdown em ordem reversa
Dois jeitos de ativar um módulo:
- Sugar — namespaces prontos (
core.API.REST(addr),core.Auth.OAuth2(...)) pra protocolos leves/stdlib. core.UseModule[T]— genérico, usado pelos protocolos com dependência pesada (GraphQL, gRPC), que não ganham sugar de propósito, pra não puxar essas dependências pra quem não usa.
Nenhum dos quatro lê variável de ambiente — endereço/porta/opções são sempre passados como argumento Go no seu próprio código.
REST — core/adapters/restapi
Não é um protocolo novo — é o mesmo core/router.Router de sempre, só que
rodando no próprio *http.Server/porta do core.Core, orquestrado por
Run()/Shutdown() em vez de fw.Run().
import "kyrux/core"
c := core.New()
r, err := c.API.REST(":8080") // *router.Router — mesma API de sempre
r.Handle("GET /ping", func(ctx *router.Context) {
ctx.JSON(200, map[string]string{"pong": "kyrux"})
})
c.Run()
GraphQL — core/adapters/apigraphql
Sem sugar (dependência pesada — graphql-go traz parser e template
próprios). Você monta o schema com a API do
graphql-go/graphql e entrega
pronto pro adapter.
import (
"github.com/graphql-go/graphql"
"kyrux/core"
"kyrux/core/adapters/apigraphql"
)
queryType := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"versao": &graphql.Field{
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (any, error) {
return "kyrux-core", nil
},
},
},
})
schema, _ := graphql.NewSchema(graphql.SchemaConfig{Query: queryType})
c := core.New()
_, err := core.UseModule[*graphql.Schema](c, apigraphql.New(":8081", schema), "api.graphql.principal")
c.Run()
Serve POST / com corpo {"query": "..."}. A GraphiQL IDE vem habilitada
por padrão, sem opção de desligar. Roda no próprio *http.Server — não é
montado no router do REST.
gRPC — core/adapters/apigrpc
Também sem sugar (HTTP/2 + runtime protobuf). O adapter só hospeda o
*grpc.Server — você gera o código do serviço a partir de um .proto
(protoc + protoc-gen-go + protoc-gen-go-grpc) e registra do jeito
normal do gRPC.
import (
"kyrux/core"
"kyrux/core/adapters/apigrpc"
)
c := core.New()
srv, err := core.UseModule[*grpc.Server](c, apigrpc.New(":9090"), "api.grpc.principal")
pb.RegisterGreeterServer(srv, &minhaImplementacao{}) // registro padrão do gRPC
// gRPC e REST coexistem no mesmo Core, portas diferentes:
r, _ := c.API.REST(":8080")
c.Run()
Shutdown chama GracefulStop() sem timeout — adicione seu próprio
watchdog se precisar de um limite de tempo.
SOAP — core/soap + core/adapters/soapclient
Implementação própria (encoding/xml + net/http, sem lib de terceiros —
o ecossistema SOAP em Go é fraco). Pensado pra casos como webservices
legados/governamentais (SEFAZ/NF-e, INSS).
Servidor — não é uma porta separada, é um http.Handler que você monta
no router do REST:
import (
"kyrux/core"
"kyrux/core/soap"
)
server := soap.NewServer()
server.Handle("SomarRequest", func(ctx context.Context, requestXML []byte) ([]byte, error) {
// parse do requestXML, monta a resposta
return responseXML, nil
})
c := core.New()
r, _ := c.API.REST(":8080")
r.HandlePrefix("/soap", server) // mesmo padrão usado pra montar métricas Prometheus
c.Run()
O roteamento é pelo nome do elemento raiz dentro de <Body> — pragmático,
não segue WSDL/SOAPAction "oficial".
Cliente, cru ou via sugar do Core:
// Cru:
client := soap.NewClient(endpoint, httpClient)
// Sugar (zero custo — é stdlib puro):
client, err := c.API.SOAPClient("principal", endpoint)
var resp somarResponse
err = client.Call(ctx, "Somar", somarRequest{A: 4, B: 5}, &resp)
// erro do lado do servidor vira *soap.Fault (errors.As)
Nenhum é lido do .env
Como o NoSQL, os quatro protocolos não têm convenção API_REST_ADDR-style
— endereço, schema, opções do grpc.Server: tudo passado como argumento Go
no seu próprio código, na hora de montar o core.Core.