Skip to content
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

API versioning #3155

Closed
wants to merge 7 commits into from
Closed

API versioning #3155

wants to merge 7 commits into from

Conversation

pwang200
Copy link
Contributor

@pwang200 pwang200 commented Nov 12, 2019

The requirements are:
https://github.com/pwang200/RippledRPCDesign/blob/API_versioning/requirement/requirements.md
The design document is:
https://github.com/pwang200/RippledRPCDesign/blob/API_versioning/design/design.md

Note that the documentation is for informational only. We will consolidate the documentation and create another PR after both API Versioning and gRPC are merged.

@pwang200 pwang200 changed the title Api versioning API versioning Nov 12, 2019
@MarkusTeufelberger
Copy link
Collaborator

How about a versioning scheme similar to Kubernetes objects where also a readiness is encoded (Alpha, Beta...)? Just an integer is a bit weak...

@intelliot
Copy link
Collaborator

In my opinion, any API version that appears in a stable release of rippled is “ready”. I don’t think there’s a need for the additional complexity that comes with alpha/beta distinctions.

@codecov-io
Copy link

codecov-io commented Nov 13, 2019

Codecov Report

Merging #3155 into develop will increase coverage by 0.06%.
The diff coverage is 94.11%.

Impacted file tree graph

@@            Coverage Diff             @@
##           develop   #3155      +/-   ##
==========================================
+ Coverage    68.94%     69%   +0.06%     
==========================================
  Files          688     688              
  Lines        55743   55799      +56     
==========================================
+ Hits         38432   38506      +74     
+ Misses       17311   17293      -18
Impacted Files Coverage Δ
src/ripple/rpc/impl/RPCHelpers.h 100% <ø> (+100%) ⬆️
src/ripple/rpc/impl/Handler.h 0% <ø> (ø) ⬆️
src/ripple/app/main/Application.cpp 59% <0%> (-0.07%) ⬇️
src/ripple/rpc/impl/RPCHandler.cpp 75.29% <100%> (ø) ⬆️
src/ripple/net/impl/RPCCall.cpp 94.69% <100%> (+0.22%) ⬆️
src/ripple/rpc/impl/RPCHelpers.cpp 87.96% <100%> (+0.42%) ⬆️
src/ripple/rpc/impl/ServerHandlerImp.cpp 87.45% <93.33%> (+1.36%) ⬆️
src/ripple/rpc/impl/Handler.cpp 96.49% <96.55%> (-1.43%) ⬇️
src/ripple/core/Stoppable.h 93.75% <0%> (-6.25%) ⬇️
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 232975b...f4661e0. Read the comment docs.

@nbougalis nbougalis requested review from mellery451 and scottschurr and removed request for mellery451 November 19, 2019 20:20
Copy link
Contributor

@nbougalis nbougalis left a comment

Choose a reason for hiding this comment

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

Looks good. Left some comments, mostly nits that are at your discretion. I'll give you a chance to consider the feedback and come back to give this a second look and sign-off on it tomorrow.

src/ripple/rpc/impl/RPCHelpers.h Show resolved Hide resolved
}
}
return RPC::APIInvalidVersion;
} else
Copy link
Contributor

Choose a reason for hiding this comment

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

This takes advantage of code that already exists in Json::Value. I like it but I'm not sure if I like it enough, especially when you consider that we will be eventually be migrating to this when it's merged into Boost. Anyways, something for you to consider:

unsigned int getAPIVersionNumber(Json::Value const& jv)
{
    static Json::Value const minVersion (RPC::APIVersionSupportedRangeLow);
    static Json::Value const maxVersion (RPC::APIVersionSupportedRangeHigh);
    static Json::Value const invalidVersion (RPC::APIInvalidVersion);

    auto requestedVersion = jv.get (jss::api_version, Json::Value(RPC::APIVersionIfUnspecified));

    if(requestedVersion < minVersion || requestedVersion > maxVersion)
        v = invalidVersion;
    
    return requestedVersion.asUInt();
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually my simplifcation doesn't quite work. It needs a further tweak.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I modified it and added a unit test.

@@ -55,6 +55,7 @@ struct Context
LedgerMaster& ledgerMaster;
Resource::Consumer& consumer;
Role role;
unsigned apiVersion;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be unsigned int (not just here, but everywhere).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I changed unsigned to unsigned int in all files in this PR.

src/ripple/rpc/impl/Handler.cpp Show resolved Hide resolved

constexpr unsigned APIInvalidVersion = 0;
constexpr unsigned APIFirstVersion = 1;
constexpr unsigned APIVersionSupportedRangeLow = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider:

APIVersionSupportedRangeLow -> ApiMinimumSupportedVersion
APIVersionSupportedRangeHigh -> ApiMaximumSupportedVersion
APIVersionIfUnspecified -> ApiDefaultVersion

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ApiMinimumSupportedVersion and ApiMaximumSupportedVersion are better names. I will change to them.

I used "ApiDefaultVersion" originally in the code too. But I feel we have two "Default Versions", (1) a network RPC request without specify a version which should default to version 1, (2) a command line request which I think should default to ApiMaximumSupportedVersion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ApiMinimumSupportedVersion and ApiMaximumSupportedVersion are changed.
APIVersionIfUnspecified is not changed.

src/ripple/rpc/impl/RPCHelpers.h Outdated Show resolved Hide resolved
constexpr unsigned APIVersionSupportedRangeHigh = 1;
constexpr unsigned APIVersionIfUnspecified = APIFirstVersion;
constexpr unsigned APIVersionCommandLine = APIVersionSupportedRangeHigh;
constexpr unsigned APIVersionRippledStartUp = APIVersionSupportedRangeHigh;
Copy link
Contributor

Choose a reason for hiding this comment

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

Considering that these two values are always likely to use a fixed version of the API, I wonder if defining values for them makes sense. We should probably just use RPC::APIVersionSupportedRangeLow directly in the places where this is used and remove APIVersionCommandLine and APIVersionRippledStartUp.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will remove APIVersionCommandLine and APIVersionRippledStartUp.

Just to confirm, we will use APIVersionSupportedRangeLow as the command line request version. I can see the benefit of both "high" and "low.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can argue for either low or high. I'm fine with using whatever is appropriate and leave that up to your judgement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed APIVersionCommandLine and APIVersionRippledStartUp, and used "high" for command line requests' versions.

@pwang200
Copy link
Contributor Author

pwang200 commented Nov 21, 2019 via email

Copy link
Contributor

@mellery451 mellery451 left a comment

Choose a reason for hiding this comment

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

👍

if(jvRequest.isObject())
insert_api_version(jvRequest);
else if(jvRequest.isArray()) {
for (Json::UInt j = 0; j < jvRequest.size(); ++j) {
Copy link
Contributor

Choose a reason for hiding this comment

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

the json arrays support range-based iteration, FWIW. Furthermore, since isMember already checks isObject, you can just just call std::for_each(jvRequest.begin(), jvRequest.end(), insert_api_version);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I changed to std::for_each(jvRequest.begin(), jvRequest.end(), insert_api_version);

I modified insert_api_version() to include isObject(). I think that is still needed. Otherwise, Value::operator[] could be called on a non-object.

* Note that APIInvalidVersion will be returned if
* 1) the version number field has a wrong format
* 2) the version number retrieved is out of the supported range
* 3) the version number is unspecified and
Copy link
Contributor

Choose a reason for hiding this comment

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

seems like case 3 should be covered by the static checks that @nbougalis suggested above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right. But I think we need both the static check (checking we don't make a mistake in coding) and the check in the function (checking network requests are acceptable).

if (jsonRPC.isMember(jss::params) &&
jsonRPC[jss::params].isArray() &&
jsonRPC[jss::params].size() > 0 &&
jsonRPC[jss::params][Json::UInt(0)].isObject())
Copy link
Contributor

Choose a reason for hiding this comment

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

jsonRPC[jss::params][0u].... might be little more concise (in general for indexing of json arrays with static values)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I changed the code.

@@ -77,6 +79,7 @@ static RPCCallTestData const rpcCallTestArray [] =
"method" : "account_channels",
"params" : [
{
"api_version" : 1,
Copy link
Contributor

Choose a reason for hiding this comment

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

if I understand correctly, this version text/field is always replaced with the max supported (?). If that's the case, I would prefer just a token string here (e.g. %MAX_API_VER%....) and then you search/replace that token in the update method (it gives a better sense of what's actually happening). If I've misunderstood what's going on, please ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great, thanks! I changed the code.

@MarkusTeufelberger MarkusTeufelberger mentioned this pull request Nov 25, 2019
@scottschurr
Copy link
Collaborator

@pwang200, FWIW, I'm recusing myself from this code review.

I have misgivings about the on-going indefinite maintenance effort that this change represents versus the benefit to users. Based on the conversations I've seen in other pull requests, I do not expect my concerns to be considered seriously at this point in time. I find myself unable to focus only on whether "an implementation has successfully realized its associated design" when I have reservations about the design itself.

Rather than increase noise with no expected change in outcome I'll simply recuse myself.

@scottschurr scottschurr removed their request for review December 2, 2019 17:11
@scottschurr scottschurr removed their assignment Dec 2, 2019
@nbougalis nbougalis mentioned this pull request Dec 31, 2019
@intelliot
Copy link
Collaborator

Note that the documentation is for informational only. We will consolidate the documentation and create another PR after both API Versioning and gRPC are merged.

@pwang200 Has the consolidated documentation been created yet?

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.

7 participants