Skip to content

Create RR.ProviderData (close #119) #169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 23, 2025
Merged

Create RR.ProviderData (close #119) #169

merged 4 commits into from
Apr 23, 2025

Conversation

mholt
Copy link
Contributor

@mholt mholt commented Apr 21, 2025

This is my proposal for being able to attach provider-specific (meta?)data to an RR. See #119.

However, since provider implementations are supposed to return the concrete struct types, not RRs, we'll likely need to add this field to all the specific structs (Address, TXT, CNAME, etc...).

I also added JSON tags to the RR struct, in preparation for 1.0, since JSON-serialization seems like it could be a common pattern. (Caddy/CertMagic do not do this, but I could see having separate JSON identifiers being handy.)

Finally, I am torn between Meta, Metadata, and ProviderData for the field name. Any thoughts?

@gucci-on-fleek What do you think?

@mholt
Copy link
Contributor Author

mholt commented Apr 21, 2025

(Super skeptical of an AI review but I'm curious, so...)

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a new field to the RR struct to store provider-specific data and adds JSON serialization tags to several existing fields to prepare for version 1.0.

  • Added JSON tags to Name, TTL, Type, and Data fields.
  • Introduced a new field, ProviderData, for provider-specific data.
Comments suppressed due to low confidence (1)

record.go:112

  • Consider adding the 'omitempty' option to the JSON tag for ProviderData (e.g., json:"provider_data,omitempty") to simplify the JSON output when no provider-specific data is present.
ProviderData any `json:"provider_data"`

@pcfreak30
Copy link

seems simple enough, and btw AI is good enough to find issues (I use it near daily), but very far away from replacing us :P.

@mholt i would add omitempty and i think this is good.

@mholt
Copy link
Contributor Author

mholt commented Apr 21, 2025

i would add omitempty and i think this is good.

Thanks; I think only ProviderData (as currently named) would ever be empty... I think? Maybe TTL, depending on when/where provider defaults are applied.

@gucci-on-fleek
Copy link
Collaborator

I also added JSON tags to the RR struct, in preparation for 1.0, since JSON-serialization seems like it could be a common pattern.

👍

Finally, I am torn between Meta, Metadata, and ProviderData for the field name. Any thoughts?

ProviderData seems like the least-worst name that I can think of. It's not an amazing name, but certainly better than anything else that I can think of.

However, since provider implementations are supposed to return the concrete struct types, not RRs, we'll likely need to add this field to all the specific structs (Address, TXT, CNAME, etc...).

Hmm, yeah, you're probably right here. So then calling .Parse() or .RR() should probably just copy over the contents of ProviderData unmodified? I guess the other options would be to provide a hook for this or unconditionally set ProviderData to nil, but neither of those seem great to me.

Or, maybe it would be better to only have ProviderData on the specific structs, and not on RR? My thinking being that you can change the Type of an RR, and providers might handle that very poorly. I don't think that this should be very much of a problem though, just something to think about.

@gucci-on-fleek What do you think?

The main problem that I can see is that we'll either need to document that RRs aren't comparable

libdns/record.go

Lines 13 to 15 in 10a2b0b

// Primitive equality (“==”) between any two [Record]s is explicitly undefined;
// if implementations need to compare records, they should either define their
// own equality functions or compare the [RR] structs directly.

which might be annoying since that means that there's no “easy” way to compare records, or document that ProviderData must be primitively-comparable, which would also be annoying since then you couldn't use it to hold a map.

The other problem that I can think of is that weird things might happen if you try and copy Records between different providers, so we should probably document either that libdns implementations must ignore invalid/unknown ProviderDatas, or that users must set ProviderData to nil when copying between zones/providers.

But overall, I'm very much in favour of this.

@mholt
Copy link
Contributor Author

mholt commented Apr 22, 2025

@gucci-on-fleek Great points, thanks!! Super helpful as usual.

I now agree that we shouldn't put this in the RR type.

It's a bit annoying, though, to put it in the individual struct types, so I just had an idea.

What about this:

type ProviderRecord struct {
	Record

	// Optional data associated with the provider serving this record.
	// See the package godoc for important details on this field.
	ProviderData any
}

This way, provider packages can return ProviderRecord values, which include custom data, and callers can still access the underlying Record independently.

Of course... this breaks callers' type-switches, which might be a deal-breaker. They'd have to specifically type-assert for this struct, then access the Record field to use it. Hmm.

Yeah, maybe just putting it on each of the individual record type structs is better. I'll work on that.

@mholt
Copy link
Contributor Author

mholt commented Apr 22, 2025

@gucci-on-fleek Okay, I reworked it so that ProviderData is in each individual struct type, not the RR struct. I also added some package-level godoc surrounding it.

Since packages are supposed to return the individual struct types anyway, they can just attach their custom data in this field, and callers' type assertions will still work. Obviously, the provider-specific data is lost with RR() (and thus, Parse() does not populate it), but that's OK since the RR type is meant to be more generic/portable, and comparable.

@mholt mholt marked this pull request as ready for review April 22, 2025 16:58
@mholt mholt requested a review from gucci-on-fleek April 22, 2025 16:58
gucci-on-fleek
gucci-on-fleek previously approved these changes Apr 23, 2025
Copy link
Collaborator

@gucci-on-fleek gucci-on-fleek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, hopefully this helps make it easier to port implementations to v1.0.

Co-authored-by: Max Chernoff <git@maxchernoff.ca>
@mholt mholt merged commit e0df105 into master Apr 23, 2025
@mholt mholt deleted the providerdata branch April 23, 2025 13:27
@mholt
Copy link
Contributor Author

mholt commented Apr 23, 2025

Awesome, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants