feat: Add HATEOAS link support for subscriber resources with navigation and action links

- Add Link struct with href, rel, and optional type fields
- Add Links map type for HATEOAS link collections
- Add SubscriberWithLinks and SubscriberListWithLinks wrapper types
- Add NewSubscriberLinks function generating self, update, delete, billing, and sessions links
- Add NewSubscriberListLinks function with self, create, and conditional next pagination links
This commit is contained in:
nutcas3
2026-05-01 09:02:12 +03:00
parent 972be70cc2
commit b2376e2133
@@ -0,0 +1,79 @@
package models
import "fmt"
// Link represents a HATEOAS link
type Link struct {
Href string `json:"href"`
Rel string `json:"rel"`
Type string `json:"type,omitempty"`
}
// Links represents a collection of HATEOAS links
type Links map[string]Link
// SubscriberWithLinks represents a subscriber with HATEOAS links
type SubscriberWithLinks struct {
Subscriber
Links Links `json:"_links"`
}
// SubscriberListWithLinks represents a subscriber list with HATEOAS links
type SubscriberListWithLinks struct {
Subscribers []SubscriberWithLinks `json:"subscribers"`
NextCursor string `json:"next_cursor,omitempty"`
HasMore bool `json:"has_more"`
Links Links `json:"_links"`
}
// NewSubscriberLinks creates HATEOAS links for a subscriber
func NewSubscriberLinks(baseURL string, subscriber *Subscriber) Links {
return Links{
"self": {
Href: fmt.Sprintf("%s/api/v1/subscribers/%d", baseURL, subscriber.ID),
Rel: "self",
},
"update": {
Href: fmt.Sprintf("%s/api/v1/subscribers/%d", baseURL, subscriber.ID),
Rel: "update",
Type: "PUT",
},
"delete": {
Href: fmt.Sprintf("%s/api/v1/subscribers/%d", baseURL, subscriber.ID),
Rel: "delete",
Type: "DELETE",
},
"billing": {
Href: fmt.Sprintf("%s/api/v1/subscribers/%d/billing", baseURL, subscriber.ID),
Rel: "billing",
},
"sessions": {
Href: fmt.Sprintf("%s/api/v1/subscribers/%d/sessions", baseURL, subscriber.ID),
Rel: "sessions",
},
}
}
// NewSubscriberListLinks creates HATEOAS links for subscriber list
func NewSubscriberListLinks(baseURL string, cursor string, limit int, hasMore bool) Links {
links := Links{
"self": {
Href: fmt.Sprintf("%s/api/v1/subscribers?limit=%d", baseURL, limit),
Rel: "self",
},
"create": {
Href: fmt.Sprintf("%s/api/v1/subscribers", baseURL),
Rel: "create",
Type: "POST",
},
}
if cursor != "" {
links["next"] = Link{
Href: fmt.Sprintf("%s/api/v1/subscribers?cursor=%s&limit=%d", baseURL, cursor, limit),
Rel: "next",
}
}
return links
}