package sendico import ( "bytes" "context" "encoding/json" "io" "net/http" "git.sendico.io/tech/sxchnge/product/identity" merrors "git.sendico.io/tech/sxchnge/shared/errors" "go.mongodb.org/mongo-driver/v2/bson" ) func (c *Client) post(ctx context.Context, resource, requestRef string, payload any, expectedStatus int) (receiptDTO, error) { var receipt receiptDTO token, err := c.token() if err != nil { return receipt, err } var body []byte if payload != nil { body, err = json.Marshal(payload) if err != nil { return receipt, merrors.OpaqueWrap(merrors.ErrServiceUnavailable, err, "encode Sendico request") } } req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.base+"/"+resource+"/"+c.config.OrganizationID, bytes.NewReader(body)) if err != nil { return receipt, merrors.OpaqueWrap(merrors.ErrServiceUnavailable, err, "create Sendico request") } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Request-ID", requestRef) response, err := c.http.Do(req) if err != nil { return receipt, merrors.OpaqueWrap(merrors.ErrServiceUnavailable, err, "Sendico request failed") } defer func() { _ = response.Body.Close() }() // Never decode or expose upstream error bodies, which can contain assertions. if response.StatusCode != expectedStatus { return receipt, merrors.ServiceUnavailable("Sendico request was not accepted") } decoder := json.NewDecoder(io.LimitReader(response.Body, 16385)) var envelope envelopeDTO if err := decoder.Decode(&envelope); err != nil { return receipt, merrors.OpaqueWrap(merrors.ErrServiceUnavailable, err, "decode Sendico receipt") } var trailing any if decoder.Decode(&trailing) != io.EOF || envelope.Status != "success" { return receipt, merrors.ServiceUnavailable("invalid Sendico response") } return envelope.Data, nil } func (c *Client) Register(ctx context.Context, requestRef string) (string, error) { dto, err := c.post(ctx, "individuals", requestRef, nil, http.StatusCreated) if err != nil { return "", err } return mapSubject(dto) } func (c *Client) Submit(ctx context.Context, subject, source string, facts identity.Facts) (identity.Receipt, error) { dto, err := c.post(ctx, "identity_facts", bson.NewObjectID().Hex(), mapFacts(subject, source, facts), http.StatusOK) if err != nil { return identity.Receipt{}, err } return mapReceipt(dto, subject) }