Files
magistrala/invitations/api/transport.go
T
Dušan Borovčanin f0d014eba2 NOISSUE - Move API to the common package (#2608)
Signed-off-by: Dusan Borovcanin <borovcanindusan1@gmail.com>
2024-12-19 18:29:53 +01:00

173 lines
5.0 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package api
import (
"context"
"encoding/json"
"log/slog"
"net/http"
"strings"
"github.com/absmach/supermq"
api "github.com/absmach/supermq/api/http"
apiutil "github.com/absmach/supermq/api/http/util"
"github.com/absmach/supermq/invitations"
smqauthn "github.com/absmach/supermq/pkg/authn"
"github.com/absmach/supermq/pkg/errors"
"github.com/go-chi/chi/v5"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)
const (
userIDKey = "user_id"
domainIDKey = "domain_id"
invitedByKey = "invited_by"
relationKey = "relation"
stateKey = "state"
)
func MakeHandler(svc invitations.Service, logger *slog.Logger, authn smqauthn.Authentication, instanceID string) http.Handler {
opts := []kithttp.ServerOption{
kithttp.ServerErrorEncoder(apiutil.LoggingErrorEncoder(logger, api.EncodeError)),
}
mux := chi.NewRouter()
mux.Group(func(r chi.Router) {
r.Use(api.AuthenticateMiddleware(authn, false))
r.Route("/invitations", func(r chi.Router) {
r.Post("/", otelhttp.NewHandler(kithttp.NewServer(
sendInvitationEndpoint(svc),
decodeSendInvitationReq,
api.EncodeResponse,
opts...,
), "send_invitation").ServeHTTP)
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
listInvitationsEndpoint(svc),
decodeListInvitationsReq,
api.EncodeResponse,
opts...,
), "list_invitations").ServeHTTP)
r.Route("/{user_id}/{domain_id}", func(r chi.Router) {
r.Get("/", otelhttp.NewHandler(kithttp.NewServer(
viewInvitationEndpoint(svc),
decodeInvitationReq,
api.EncodeResponse,
opts...,
), "view_invitations").ServeHTTP)
r.Delete("/", otelhttp.NewHandler(kithttp.NewServer(
deleteInvitationEndpoint(svc),
decodeInvitationReq,
api.EncodeResponse,
opts...,
), "delete_invitation").ServeHTTP)
})
r.Post("/accept", otelhttp.NewHandler(kithttp.NewServer(
acceptInvitationEndpoint(svc),
decodeAcceptInvitationReq,
api.EncodeResponse,
opts...,
), "accept_invitation").ServeHTTP)
r.Post("/reject", otelhttp.NewHandler(kithttp.NewServer(
rejectInvitationEndpoint(svc),
decodeAcceptInvitationReq,
api.EncodeResponse,
opts...,
), "reject_invitation").ServeHTTP)
})
})
mux.Get("/health", supermq.Health("invitations", instanceID))
mux.Handle("/metrics", promhttp.Handler())
return mux
}
func decodeSendInvitationReq(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
}
var req sendInvitationReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
}
return req, nil
}
func decodeListInvitationsReq(_ context.Context, r *http.Request) (interface{}, error) {
offset, err := apiutil.ReadNumQuery[uint64](r, api.OffsetKey, api.DefOffset)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
limit, err := apiutil.ReadNumQuery[uint64](r, api.LimitKey, api.DefLimit)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
userID, err := apiutil.ReadStringQuery(r, userIDKey, "")
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
invitedBy, err := apiutil.ReadStringQuery(r, invitedByKey, "")
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
relation, err := apiutil.ReadStringQuery(r, relationKey, "")
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
domainID, err := apiutil.ReadStringQuery(r, domainIDKey, "")
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
st, err := apiutil.ReadStringQuery(r, stateKey, invitations.All.String())
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
state, err := invitations.ToState(st)
if err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, err)
}
req := listInvitationsReq{
Page: invitations.Page{
Offset: offset,
Limit: limit,
InvitedBy: invitedBy,
UserID: userID,
Relation: relation,
DomainID: domainID,
State: state,
},
}
return req, nil
}
func decodeAcceptInvitationReq(_ context.Context, r *http.Request) (interface{}, error) {
if !strings.Contains(r.Header.Get("Content-Type"), api.ContentType) {
return nil, errors.Wrap(apiutil.ErrValidation, apiutil.ErrUnsupportedContentType)
}
var req acceptInvitationReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, errors.Wrap(apiutil.ErrValidation, errors.Wrap(err, errors.ErrMalformedEntity))
}
return req, nil
}
func decodeInvitationReq(_ context.Context, r *http.Request) (interface{}, error) {
req := invitationReq{
userID: chi.URLParam(r, "user_id"),
domainID: chi.URLParam(r, "domain_id"),
}
return req, nil
}