Feature Request: Support deprecation of service functions in Candid

We can add deprecations in Rust using this. It’s a way to mark your public API methods as deprecated.

It would be awesome for Candid to recognize this deprecation and make it part of the declarations.

That way frontend types can utilize TypeScript’s JSDoc interpretation and surface the deprecation in the frontend code where the API is being consumed. Like this

So, essentially if I have Rust code like this

#[deprecated = "Use function2"]
pub fn function1() { }

it will generate Typescript/JS bindings like this

/** @deprecated Use function2 */
'function1': ActorMethod<..>

Which in turn will create the deprecated lint warning and the strikethrough over the code in the frontend call sites where this method is called.

That way I’m communicating deprecation intent directly with the frontend devs who are consumers of the API without confusing back and forths.
And once they’ve upgraded their code to remove usage of the deprecated API, they can be removed from the backend codebase. And CI can run compile time checks on frontend TypeScript, to catch any errors, in case API still in use.

Thoughts?

@chenyan @kpeacock

2 Likes

One value proposition of the IC is that canister methods can be invoked by other canisters, and the main purpose of Candid is describe such public interfaces. You can not generally know which other canister depend on yours and when those will be updated, or if ever. So in the interest of not breaking others, removal of public methods (or other backwards-incompatible changes) should generally be avoided on the IC. In that light, deprecation of methods ought to be discouraged as well.

2 Likes

But a deprecation is not removal. A deprecation is a notice to the consumer of the API that this might get removed in the future.

I’m not convinced that the argument of discouraging methods works in this case. It’s about giving developers more power and choice if they choose to use it.

Some thoughts to support the opinion above:

  • Other standards that perform a similar objective as Candid such as protocol buffers and GraphQL support deprecation as shown here and here

  • As you pointed out, canisters exposing public APIs can be called by other canisters. These canisters could either be canisters belonging to the same project/backend or could be external canisters that are not controlled by the callee canister developers.

    IF the calling canister is controlled by developers who control the callee canister, in that case, they already have control of both and it is an intentional change.

    IF however, the calling canister is a third party developer and they are basing their business/application on the API provided by another developer, they should base it on a different trust assumption. That either the callee canister is a blackholed canister and cannot be upgraded or that the callee canister is controlled by an autonomous entity like an SNS DAO

  • Finally, smart contracts (canisters) on the IC have the super power of upgradability. However, saying that upgrades should only be additive in nature is trying to limit practical application development to unrealistic standards.

    Frankly, there’s nothing stopping an application developer from ripping out any public API that they choose for a canister they are a controller of.

    Deprecation just provides a safer way to do it where they can communicate their intent better to consumers of the API

Thoughts?
@rossberg

1 Like

It’s not a one-way street, though. With more power on one side you have less on the other: devs can rely less on other devs’ services to get their job done.

Such an assumption would make canister API reliability and upgradability mutually exclusive, which would be defeating the purpose.

True at the moment, but that doesn’t imply that they normally should. Or that there should be tool support that encourages it.

That all said, I agree that there is still value in deprecating API as a way to steer active dependencies towards superior API. But you must always assume that there will remain customers depending on the old version. That’s the price of an open platform. The only methods you can safely change are those that already access-check their caller.

Thank you. Always grateful to be able to share in your wisdom.

You mentioned open platforms. The web and its gateway, the browser also participate in deprecating APIs and nudging users towards newer/improved alternatives.

Some examples from a quick search:

I’ll tag a couple of other Rust devs I respect and check if they think this is worth pursuing.

@lastmjs @hpeebles @senior.joinu

I just gonna say that the web is the worst possible example to look at when it comes to anything having to do with good software engineering practices. : )

2 Likes

I think it’s a good feature to preserve comments in the Candid API when generating language bindings. It encourages more documentation. I create an issue to track this: Preserve comments when generating language bindings · Issue #393 · dfinity/candid · GitHub

6 Likes

I literally asked myself this question (" Preserve comments when generating language bindings") again and noticed the related open issue hasn’t moved in a year and a half. Do you know if there is any plan to support this feature in the future?

2 Likes