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

Add basic Get and Put Api signatures along with protobuf setup #1

Merged
merged 1 commit into from
Dec 21, 2022

Conversation

G8XSU
Copy link
Collaborator

@G8XSU G8XSU commented Oct 6, 2022

Add Basic api signatures
Main file to review : src/main/proto/ess.proto

This will auto-generate required request/response objects.

Note: Since we didn't define the "service" proto, its not going to generate any grpc service stubs.
Here protobuf is only being used as a binary serialization format for request and response objects.(instead of writing custom binary serialization or json). This helps both client and server to create requests/response like class instances with ease.
This payload will be used as binary body in http-rest post requests.

Apart from that it is mostly auto-generated setup for gradle project.

Things like Auth will be added once we add API for creating a "store".

Currently this api can be used with any of the approach mentioned in doc, that is "Independent State Updates", "Global State Counter", "Incremental State Updates".
LDK will be using "Global State Counter", different applications might choose different approaches based on their needs.
Doc: https://docs.google.com/document/d/1mhTAnkXAtxPQRsn17gbEPIN5G8OW2h619f_yk8CXJTE/edit?usp=sharing

}
message GetResponse {
bool success = 1;
KeyValue value = 2;
Copy link
Member

Choose a reason for hiding this comment

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

is it useful to return just one value, or does it make more sense to return everything with a certain key prefix? for VLS at least we always want to get a complete snapshot of the storage for a node when we do perform a get. does LDK intend to make single item retrievals?

Copy link
Collaborator Author

@G8XSU G8XSU Oct 7, 2022

Choose a reason for hiding this comment

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

regarding "return everything with a certain key prefix" => i thought about it but this makes for an unbounded query on server-side hence we should be avoiding it
single get does mean some additional work for client.

Regarding "list by key prefix" => this in intended to be solved by listKeys api which will be a paginated api. For LDK as well, we have use-case of reloading parts of snapshot. (This will be done after computing version difference of keys b/w client and server-side)

I had added "Batch" operation support as "future item" in doc, but that also won't solve this problem because there will still be some batch limit. Client needs to use versioning to ensure consistent state instead of relying on getting everything at once in consistent fashion.
Another reason, I was being bit conservative about batch operations is because we intend to support storing values upto ~5MB, even a 10 item get might mean 50MB response depending on client-application.

Let me know if that works.

Side note: Currently this api can be used with any of the approach mentioned in doc, that is "Independent State Updates", "Global State Counter" or "Incremental State Updates". LDK will be using "Global State Counter"

Copy link
Member

Choose a reason for hiding this comment

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

I don't see "Independent State Updates" in the doc. However, that sounds like the approach that VLS would use. But would be interested in hearing more.

So I think the plan with listKeys would work, but we will need this sooner rather than later, since otherwise there is no way to discover what is in the store.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, LDK needs listKeys and getKeysSummary immediately as well.
Just didn't include it in this commit. Wanted close on basic get and put first.

Heading was named slightly different. Added "Independent State Update" to that heading.

string key = 1;

// Write will only succeed if current DB version against key is same as in request.
int64 version = 2;
Copy link
Member

@devrandom devrandom Oct 7, 2022

Choose a reason for hiding this comment

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

should document here what is the starting version number - i.e. when a key does not exist, should the version specified here be -1 or 0?

also, it may make more intuitive sense to provide current_version + 1 (i.e. the new version) here instead of current_version, but this is a matter of taste

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think from client perspective they will have to maintain a current version of object that they have in-memory or secondary store.
It could be more intuitive to start with 0 as first version as it will be same for client and they just call with their current version at-hand instead of any special handling.

Will add it to docs.

@devrandom
Copy link
Member

I think we should never check in binaries to our repos, including gradle-wrapper.jar. I know it's convenient, but it's also a security problem. It's easy enough to provide instructions in the README or add a build script to select the right version. See https://stackoverflow.com/a/28473686

@G8XSU G8XSU marked this pull request as ready for review October 10, 2022 20:29
@jkczyz jkczyz self-requested a review October 20, 2022 17:15
Comment on lines 5 to 9
service EncryptedStorageService {
rpc get(GetRequest) returns (GetResponse);
rpc put(PutRequest) returns (PutResponse);
//TODO: Add getKeysSummary (Gives version numbers for all keys in a store) and list by prefix API's
}
Copy link

Choose a reason for hiding this comment

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

What is being "get" or "put"? I'd recommend following these naming conventions for both method and type names:

https://cloud.google.com/apis/design/naming_convention

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, changed it to GetObjectRequest and PutObjectRequest

src/main/proto/ess.proto Outdated Show resolved Hide resolved
string key = 1;

// Write will only succeed if current DB version against key is same as in request.
int64 version = 2;
Copy link

Choose a reason for hiding this comment

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

Do all KeyValues in a PutRequest need to have the same version or can they differ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Every key will have its own version. so they can differ.

Comment on lines 30 to 34
/*
If present, write will only succeed if current DB globalVersion against a storeId is
same as in request.
*/
optional int64 globalVersion = 2;
Copy link

Choose a reason for hiding this comment

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

Could you flesh out all the docs in this file? At a high-level, the versioning scheme should be defined.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Sounds good, i will write a basic explanation in docs.
Hoping to write a much more detailed api doc after impl though.

Copy link

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Can you provide more justification for why there's protobufs to talk to the server? Why is it insufficient to do a simple HTTP(S) GET/PUT RESTful API? It seems this will run over HTTP(S) anyway, so that seems strictly simpler for both client and server? Am I missing something?

@devrandom
Copy link
Member

I think the request/response bodies may be complex enough that protobufs and strongly-typed bindings to them would be an improvement over JSON. Also, more compact / performant.

Ref: https://en.wikipedia.org/wiki/Keyspace_(distributed_data_store)
It is up to clients to use single or multiple store's for their usage.
*/
string storeId = 1;

Choose a reason for hiding this comment

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

I don't understand why we want this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Its for key grouping,
If service owner wants to implement following:

  • client-isolation/rate-limiting/throttling
  • authorization
  • billing etc.
  • Also I could delete a store which is no longer being used.
    They can do this based on this identifier.

Choose a reason for hiding this comment

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

The service owner definitely wants to implement client isolation, I think that's required for this API fundamentally. My question is why we need this on top of that. Given that clients can only store some limit amount and the clients are all isolated, I don't understand why we need clients to support different storage sections. Can that not also be implemented as just having different "clients"? We're not building an enterprise-scale storage platform for a user, we're building an enterprise-scale storage platform to store data for a lot of small users, I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is exactly that, building "enterprise-scale storage platform to store data for many users".
storeId is an abstraction for clientId.
A client can have multiple stores if they choose to but most might just use single store, its up to them.
Its just like we can create multiple EBS instances and its not assumed that we will only use one.

storeId is client isolation at storage layer, can think of it as userId.

message KeyValue {
string key = 1;

int64 version = 2;

Choose a reason for hiding this comment

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

Hmm, isn't it kinda awkward on the server to have both a global-version and versions on all the KV entries? Does it make sense to have it in the API explicitly when it will ultimately be implemented by having a dummy "globalVersion" key that could just be a separate KeyValue done on the client side?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Internally it is implemented like just another KV entry only.
We can consider it but i preferred this minor implementation complexity on server side than on client side.

We don't want to explain to clients every time that this is how you should be using this if you want global consistent writes. From multiple discussions i have had on versioning of state, it looks like devs could miss this detail if api is not explicit about it.
By doing so, we can give clients guidance on two popular options for using versioning. And they can simply choose based on their requirements.

(Using GlobalVersioning is optional for clients, for LDK it is required, VLS might not need it.
For single-device access globalVersion is not required.)
Provides a simpler interface for clients using single-item writes who don't care about multi-item transactions.
Using transactions for doing global consistent write is more of an implementation detail.

Choose a reason for hiding this comment

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

I guess my question is more if we're controlling the client code or not. I understood that, generally, users wouldn't be exposed to the protobufs here, they'd use some libvss-{rust,java,etc}-client library. Including the globalversion K-V can then be done at the client level without users being exposed to it.

@TheBlueMatt
Copy link

I think the request/response bodies may be complex enough that protobufs and strongly-typed bindings to them would be an improvement over JSON. Also, more compact / performant.

I'm not sure why they would be? I agree let's avoid JSON, but there's not that many fields here, PUT is the only complicated one, and its really just a set of K-Version-V tuples. That could be sent in a format way simpler than protobufs?

@devrandom
Copy link
Member

I think the request/response bodies may be complex enough that protobufs and strongly-typed bindings to them would be an improvement over JSON. Also, more compact / performant.

I'm not sure why they would be? I agree let's avoid JSON, but there's not that many fields here, PUT is the only complicated one, and its really just a set of K-Version-V tuples. That could be sent in a format way simpler than protobufs?

What did you have in mind? (It's probably best to have a format that is commonly used in web API client code for various languages.)

@TheBlueMatt
Copy link

I mean pick a simple format. bencoding or something equally simple makes sense to me. binary packing works fine to me, or hex encode it, csv it, i dunno, doesn't matter. Protobufs are a lot of complexity and language support is generally good, but not always great. Something that you can hand-write in any language seems like it would be better than protobufs.

@devrandom
Copy link
Member

It sounds like you'd end up supporting client libraries for different languages, people writing sub-standard encoders/decoders, etc.

@TheBlueMatt
Copy link

TheBlueMatt commented Nov 1, 2022

Right, sub-standard encoders for Protobufs is an issue ;). If the encoding were simpler sub-standard encoders should be only a performance issue.

@G8XSU
Copy link
Collaborator Author

G8XSU commented Nov 3, 2022

protobuf/grpc is industry standard and is simple.
Main reasons for protobuf and grpc being:

  1. Highly performant
  2. Easier to maintain backwards compatibility (cannot emphasize enough)
  3. Cross language support (Platform-agnostic)
  4. Makes it easier to support http/2 and async requests (we also won't have to worry about connection/channel reuse/multiplexing)

There is no way, we should be writing custom encoding/format for this. (i thought @devrandom concern about sub-standard serde was on this.)
I also think there are reasonable grpc/protobuf third party libs available in languages other than the officially supported ones. for e.g. (hyperium/tonic)

The request/response objects are complex enough, there are two more api's yet to be added, we will be adding more fields and metadata to schema as server matures.

Also, i thought we had decided on it in Meeting Notes Oct 5th: "Will use java and grpc to build backend"

@Jasonvdb
Copy link

Jasonvdb commented Nov 4, 2022

Sorry wasn't in the meeting. Curious though what were the reasons java was chosen?

@G8XSU
Copy link
Collaborator Author

G8XSU commented Nov 4, 2022

@Jasonvdb
Main reasons for java were : Native cloud support by official SDK's as well as related ecosystem for database accessors.
Rust doesn't have production ready SDK's from cloud providers yet. (Most are in beta, developer preview)
Client side will be written in rust and client-native languages, communicate with server side.
Also, Its not a one-way door decision, same proto definition can be re-implemented by another service.

@TheBlueMatt
Copy link

Main reasons for protobuf and grpc being:

I get the sense grpc support across different languages is more mixed than protobuf. For example going grpc will mean that you cannot talk to a VSS server from entirely within a javascript context, which I think is a no-starter. I think we kinda have to go the HTTPS route for the actual talking, even if we use protobufs for the contents.

Highly performant

This depends on the specific language we're talking about? But, yes, most languages have at least a reasonably good protobuf library.

Easier to maintain backwards compatibility (cannot emphasize enough)

If we go the grpc route I agree with you, but I don't think we can. With HTTPS we get this for free - /v1, /v2, etc :)

Cross language support (Platform-agnostic)

Right, see my above list of suggested alternatives, this is pretty easy to match :).

There is no way, we should be writing custom encoding/format for this.

I don't really understand peoples' hesitance to do this - if we're concerned about adding fields and backwards compat and all that good stuff I may agree, but I don't think that's a concern - and for a three-tuple (where one element is fixed-length) almost anything is reasonable :)

Also, i thought we had decided on it in Meeting Notes Oct 5th: "Will use java and grpc to build backend"

Ah, I recall the java conclusion, I may have missed the grpc note, sorry about that.

@jkczyz
Copy link

jkczyz commented Nov 7, 2022

Not sure if I have all the nuances of the conversations, but I believe gRPC exposes an HTTP interface with /v1, /v2, etc. style versioning. Resources:

@TheBlueMatt
Copy link

Right, so let's just stick with an HTTP interface :). I'm not sure I understand what the specific value of grpc is on top of a simple HTTP interface if we have to support at least HTTP anyway?

@devrandom
Copy link
Member

There is no way, we should be writing custom encoding/format for this.

I don't really understand peoples' hesitance to do this - if we're concerned about adding fields and backwards compat and all that good stuff I may agree, but I don't think that's a concern - and for a three-tuple (where one element is fixed-length) almost anything is reasonable :)

I haven't convinced myself yet that the API will remain simple.

@TheBlueMatt
Copy link

I haven't convinced myself yet that the API will remain simple.

Right, I think my point here was that the API today is super duper trivially simple, and if we ever need to change that we can switch to protobuf in a /v2/ API.

Copy link

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

In general, I think we should flesh out all the documentation and have some top-level or message-level docs explaining the versioning scheme. See comments for some details.

string key = 2;
}
message GetObjectResponse {
KeyValue value = 2;
Copy link

Choose a reason for hiding this comment

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

Do we need to return the key?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, its generally a good practice to return key as well.
This is helpful if and when we want to have batch api in future. Makes for a consistent code.
Also slightly easier to implement client side parallel batch calls.

/*
If present, write will only succeed if current DB globalVersion against a storeId is
same as in request.
Client is expected to send their current global version at hand.
Copy link

Choose a reason for hiding this comment

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

How does the client track the global version and when may it be different from the server?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Client side and server side global version only diverge in case of multiple devices.
I.e. multiple client-side updating same state.
Just like they keep track of current value/version against a key, they will need to store global version(either in-memory or disk)
We will provide a vss-client which will do all of this for them.

For first write of store, version should be '0'. If write succeeds, clients must increment
their global version(on device) by 1.

Requests with conflicting version will fail with [`ConflictException`] as ErrorCode.
Copy link

Choose a reason for hiding this comment

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

Will this return the actual global version on failure? Or does the client need to do something to get in sync?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, it does not. Returning it from here doesn't add much value and keeps api simpler (and can have some race-conditions if used without considering some edge cases.)
ConflictException indicates that their view of store is out-of-sync. And they need to re-sync their view by fetching all key-versions and global version from server.
And for the keys having different version on server, client will need to update their view(can be done lazy).
(This is will also be provided as implemented method in vss-client)

Copy link

Choose a reason for hiding this comment

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

Is there a method for fetching everything? A client may not have all keys if another client wrote a new key.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes it will be in subsequent PR once we have get and put.

app/src/main/proto/vss.proto Show resolved Hide resolved
/*
If present, write will only succeed if current DB globalVersion against a storeId is
same as in request.
Client is expected to send their current global version at hand.
Copy link

Choose a reason for hiding this comment

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

"at hand" is a little vague. We should spell out what this means.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Clients are expected to store version against every key locally.
When initiating a PutRequest, request should contain current version for that key."
Let me know if this sounds better or we need to add more context.

Copy link

Choose a reason for hiding this comment

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

Not sure I follow what is meant by "store version against every key locally". This comment is on globalVersion, and my understanding is there is one global version for a store.

@G8XSU G8XSU requested a review from TheBlueMatt November 30, 2022 19:59
Copy link

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Could you go ahead and push any updated docs? Would be easier to read with new commits rather than looking at comments.

/*
If present, write will only succeed if current DB globalVersion against a storeId is
same as in request.
Client is expected to send their current global version at hand.
Copy link

Choose a reason for hiding this comment

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

Not sure I follow what is meant by "store version against every key locally". This comment is on globalVersion, and my understanding is there is one global version for a store.

Comment on lines 26 to 27
For first write of store, version should be '0'. If write succeeds, clients must increment
their global version(on device) by 1.
Copy link

Choose a reason for hiding this comment

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

Should make it clear the version is incremented on the next put request?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added clarification

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
For first write of store, version should be '0'. If write succeeds, clients must increment
their global version(on device) by 1.

Requests with conflicting version will fail with [`ConflictException`] as ErrorCode.
Copy link

Choose a reason for hiding this comment

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

Is there a method for fetching everything? A client may not have all keys if another client wrote a new key.

@G8XSU G8XSU requested a review from jkczyz November 30, 2022 22:21
Copy link

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

I assume authentication is handled at the HTTP layer?

their corresponding key versions(client-side) by 1. These updated key versions should be used in
subsequent PutRequests for the keys.

Requests with conflicting version will fail with [`ConflictException`] as ErrorCode.

Choose a reason for hiding this comment

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

Should we include which version value was wrong in the error result? That way clients know what to download?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Clients might need to sync their whole view depending on conflict and their usage.
Conflict could be either due to key versions or global version.
ErrorResponse should be simple and adding all this info could complicate it. Instead it is easier to re-use existing api's for the functionality.

option java_multiple_files = true;
package org.vss;

message GetObjectRequest {

Choose a reason for hiding this comment

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

Don't we need an API to fetch the list of keys stored (and maybe the versions of them)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, its part of separate api, will add it in following PR's

Copy link

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Could you add documentation to all messages and fields? The message docs can go into detail about the usage scenario. And fields can explain anything that should be considered when setting them.

/*
If present, write will only succeed if current DB globalVersion against a storeId is
same as in request.
Client is expected to global version against store. And PutRequest should contain
Copy link

Choose a reason for hiding this comment

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

Looks like there's a word missing in the sentence.

Copy link
Collaborator Author

@G8XSU G8XSU Dec 1, 2022

Choose a reason for hiding this comment

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

Done, 👍

Regarding "The message docs can go into detail about the usage scenario. And fields can explain anything that should be considered when setting them."

I created an issue and we will add these details once we have an implementation.
#3

Copy link

Choose a reason for hiding this comment

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

Could we do this now? Doing it in a follow-up just adds extra review burden.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have added lot more docs now for every field. But there are still many things which we could cover in here.
I didn't want to stall this PR for docs changes and want to close on interface.

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
@G8XSU G8XSU requested review from TheBlueMatt and jkczyz December 6, 2022 20:16
Copy link

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

I didn't comment exhaustively on it, but note my comment on using the definite article "the" where appropriate. We'll want to me a little more formal in the language used in docs than everyday informal speech.

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
their global version(client-side) by 1. This updated global version should be used in subsequent
PutObjectRequests for the store.

Requests with conflicting version will fail with [`ConflictException`] as ErrorCode.
Copy link

Choose a reason for hiding this comment

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

The [] notation is used in rustdocs for linking. Does proto doc generation have a similar feature?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no, there is no such feature afaik.
Here, i was just using it to quote specific object-field, replaced it with just ` quotes

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
Copy link

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Largely looks good modulo commented on grammar and nits.

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
Copy link

@jkczyz jkczyz 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. Just a few minor comments.

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved

message GetObjectRequest {

// StoreId: All APIs operate within a single storeId.
Copy link

Choose a reason for hiding this comment

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

Only use one space between // and text throughout.

Copy link

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

@devrandom Could you take another pass?

app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
app/src/main/proto/vss.proto Show resolved Hide resolved
app/src/main/proto/vss.proto Outdated Show resolved Hide resolved
It is meant to be read and understood programmatically by code that detects/handles errors by
type.
*/
ErrorCode errorCode = 1;
Copy link
Member

Choose a reason for hiding this comment

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

I would not have ErrorCode track the HTTP error codes in any way, to prevent the user from making assumptions about any correlation between the two. in general, we may have error conditions in the future that don't fit any HTTP error code.

message PutObjectResponse {
}

// When HttpStatusCode is not ok (200), the response `content` contains a serialized ErrorResponse
Copy link
Member

Choose a reason for hiding this comment

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

unfortunately, I don't think all gRPC client libraries let you access the HTTP error code, or parse the body if the HTTP code is 4xx.

I recommend looking into the tonic Rust crate to see what is available at least in the Rust case. in particular see the Status struct, which is returned in the failure case.

and lastly, I think all bets are off if the HTTP code is 5xx, because that could be caused by an intermediate proxy and might not reach the gRPC server at all.

Copy link
Member

Choose a reason for hiding this comment

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

also, consider the gRPC native error codes - https://grpc.github.io/grpc/core/md_doc_statuscodes.html

for example, the FAILED_PRECONDITION code might be a good match for an incompatible version in a Put.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

since it is not a grpc service,
we cannot use status struct acc. to grpc protocol (it uses http/2 trailing headers)
and we don't need to follow grpc status codes.

In case someone wants to create a grpc service, they could use status struct and serialize this errorResponse message inside status.

Copy link
Member

Choose a reason for hiding this comment

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

I somehow missed that the current PR is not for gRPC anymore. is there more information about the underlying protocol - I don't immediately see it in the PR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since we didn't define the "service" proto, its not going to generate any grpc service stubs.
Here protobuf is only being used as a binary serialization format for request and response objects.(instead of writing custom binary serialization or json). This helps both client and server to create requests/response like class instances with ease.
This payload will be used as binary body in http-rest post requests. I think we will need to add this detail on overall project readme for vss-server as well as some client with examples.

Copy link
Member

Choose a reason for hiding this comment

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

OK, sounds good

Copy link

Choose a reason for hiding this comment

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

FWIW, the Status error codes are meant to be protocol-agnostic.

https://cloud.google.com/apis/design/errors

Copy link
Collaborator Author

@G8XSU G8XSU Dec 21, 2022

Choose a reason for hiding this comment

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

Whether we use HttpStatus codes or protobuf status codes,
the same concern remains that in future we might want to introduce error conditions which donot map directly or have one to many mapping.
Removed this association as part of another comment

@G8XSU
Copy link
Collaborator Author

G8XSU commented Dec 21, 2022

Changed to underscore_separated_names for field names and kept camel case for structs. (acc. to protobuf generation guideline).
Synced with Matt offline and will be going ahead and merging this.

@G8XSU G8XSU merged commit 7362e90 into lightningdevkit:main Dec 21, 2022
@G8XSU G8XSU mentioned this pull request May 10, 2023
31 tasks
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.

5 participants