Closed cschuchardt88 closed 12 months ago
Before i make client can someone make sure we are going to use this?
@cschuchardt88, It is a mechanism that many developers requested to us in the past, as far as I can remember. In my opinion, many people would use it. I would like to hear as well from other developers from the Python team that already did something similar in the past: @ixje @lllwvlvwlll
One point that worries me a little bit is about the maintenance and security of some calls, how could we make it more generic related to the current RPC Server plugin or RPC Client? That would gives us less burden for keeping this plugin up to date.
Swagger can be added to the list
The RestServer implements the same things for Kestrel as RpcServer does. Plus newer features. Everything is configurable and can be turned off. For added security you can enable basic authentication and/or https, with the ability to use a forward proxy. Also you have the ability to disable controllers and by default we disable WalletController. So if anyone want to make this plugin be public on a public node. We don't want people trying to open wallets or search around on the node for one. This uses middleware to block the controllers from ever being loaded. "DisableControllers": [ "WalletController" ]
. Trying to access disabled controller routes with end in a 404 response from the server.
This is very generic but may appear not to be. Most the code is Model/Json converters for serializing the Models to JSON and JSON to Objects. These include UInt160, UInt256, StackItem, Transactions and Blocks to just name a few. If the application breaks I have Middleware set to not leak sensitive information to the end user. Server will return generic responses like see below. In the event of a crash of the application from any controller will result in a generic exception json response. To ensure applications that are consuming this RestServer will not have inconsistent responses for crashes or errors. Also any exception that is thrown will also result in error response like see below. So instead of returning your own response in a plugin for example with your own error. You would just throw an exception and the result will be 400 response with see below as example
{
"code": 1001,
"name": "ParameterFormatException",
"message": "Parameter hash is in an invalid format."
}
if you have a look at theses files RestServerPlugin.cs
, RestServerSettings.cs
and RestWebServer.cs
they can tell the whole story of what's going on and give you the idea of what is happening and the working of the application.
@shargon yes I can add it.
Edit: I added swagger to the RestServer per @shargon
Swagger can be added to the list
Is this what you were looking for? See Attachment of results. I don't use swagger, but i have implemented it for you. I have implemented it in the pass before, but just don't like using it. Swagger Test.pdf
Edit: also do you care if i use xunit testing framework instead of microsofts. Also would like a fully featured wallet api?
@vncoelho currently the state of plugin is sound. The burden would add to new features like something in Kestrel server Or even maybe change swagger settings (which can be an easy task). Other than that the plugins get automatically loaded and no reference needs to be referenced back to this assembly. All plugins are independent from one another. Top post i posted has a link to my repo with an example of a "dummy example plugin" for adding to this Rest server.
I designed this plugin to have no restrictions for other plugins. To allow them do what they want. For example Route, Route parameters, parameters type, erroring, throwing exceptions and more. the code uses generic error middleware for responses. So other client that program against this api won't crash or get something unexpected results. Like an developer exception page. All default settings for RestServer have been removed and i set everything manually. If you like reading code have a look at RestWebServer.cs
. Reusability was thought of in the design pattern of this plugin. No dependency injection is required as well.
WorkFlow The workflow is a simple one, it follows the premise of MVC without the views. Just simple "API Controllers". You also have the ability to disable controllers and everything is configurable. No dependency reference to this assembly for plugins or soon to come RestClient. So users can easily add RestClient into other dotnet frameworks like dotnet Maui and Unity. RestClient will not require dependency on Neo.dll. Everything is server side.
Need more information or if i wasn't clear enough let me know.
@shargon is this how you were envisioning it? Also you do know each plugin would have to do this and update the RestServer.xml file for Swagger right? If you don't already know, Swagger uses code comments to do so, unless you use Swagger's Annotations.
Edit: For the xml file I think I have it figured out. For other plugins.
RestClient is here at my Repo. Reason being is that I tried adding the client to this pull request but the build props won't let you remove the neo.dll package.
The reason is that we want a DotNet Standard 2.1 client for support in Unity, Xamarin, Mono and all other dotnet frameworks.
This is Ready for testing. Check top post for RestServer Plugin binaries (Only has necessary files).
Just need input on the Swagger endpoint descriptions. For Example when you get the exception It will show error "If anything is invalid or request crashes." but you are able to get the real error see example in Top Post of RestClient Example. It's just the way Open API client works in visual studio, so we need to update that and all other output messages of any kind.
@shargon Swagger has limitations with polymorphism classes. There is no workarounds for this problem. Here is the problem that i am having. The document that is create by swagger and the client don't know how to make classes abstract. One example of this is StackItem's and Signer's class see below. What the client does is generate inheritance of the classes and doesn't mark them as abstract class or abstract properties. In the case of the example below it will think that the return is ONLY AndConditionModel
and this is no way to fix this currently due to the specification of Open API. Making a custom client defeats the purpose of using Swagger. So i removed swagger and started making another RestServer
version that doesn't use swagger.
Example
public abstract class WitnessConditionModel
{
public abstract WitnessConditionType Type { get; }
}
public class AndConditionModel : WitnessConditionModel
{
public WitnessConditionModel[] Expressions { get; set; }
public override WitnessConditionType Type => WitnessConditionType.And;
}
public class OrConditionModel : WitnessConditionModel
{
public WitnessConditionModel[] Expressions { get; set; }
public override WitnessConditionType Type => WitnessConditionType.Or;
}
public class GroupConditionModel : WitnessConditionModel
{
public string Group { get; set; }
public override WitnessConditionType Type => WitnessConditionType.Group;
}
You can use options.UseOneOfForPolymorphism();
@shargon there is currently a bug https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/2702 with it and i did use a workaround
options.UseOneOfForPolymorphism();
options.SelectSubTypesUsing(baseType =>
{
if (baseType == typeof(WitnessConditionModel))
{
return new[]
{
typeof(AndConditionModel),
typeof(OrConditionModel),
typeof(GroupConditionModel),
// ...
};
}
return Enumerable.Empty<Type>();
});
But the problem is the Open API client won't generate the right classes as abstract or properties as abstract because it doesn't know. Because the spec doesn't say. Now we can customize the classes to abstract but that defeats the purpose.
Edit: i researched this for a day, but all i could come up with is there is a limitation with polymorphism and abstract classes
@shargon Open API will generates classes like this see below and only have one return type of the class, in this case OrConditionModel
is the only one returned by the function out of all the Conditions
see below. But the classes are partial and can be edited. we can do that with our client, but other end users importing this swagger.json file won't know. We might get spam with issues about it.
WitnessConditionModel andcon = await restClient.TestAsync().ConfigureAwait(false);
OrConditionModel orcon = (OrConditionModel)andcon;
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class WitnessConditionModel
{
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public WitnessConditionType Type { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class OrConditionModel : WitnessConditionModel
{
[Newtonsoft.Json.JsonProperty("expressions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Collections.Generic.ICollection<AndConditionModel> Expressions { get; set; }
[Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public WitnessConditionType Type { get; set; }
}
@shargon Open API will generates classes like this see below and only have one return type of the class, in this case
OrConditionModel
is the only one returned by the function out of all theConditions
see below. But the classes are partial and can be edited. we can do that with our client, but other end users importing this swagger.json file won't know. We might get spam with issues about it.WitnessConditionModel andcon = await restClient.TestAsync().ConfigureAwait(false); OrConditionModel orcon = (OrConditionModel)andcon;
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class WitnessConditionModel { [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public WitnessConditionType Type { get; set; } } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.20.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v13.0.0.0))")] public partial class OrConditionModel : WitnessConditionModel { [Newtonsoft.Json.JsonProperty("expressions", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public System.Collections.Generic.ICollection<AndConditionModel> Expressions { get; set; } [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public WitnessConditionType Type { get; set; } }
It's strange that only one class appears, but I think that is openApi problem, it's well defined in the json
I did make an issue about it on their github https://github.com/RicoSuter/NSwag/issues/4506#issue-1876376051
What a beautiful and elegent coding style.
This is at the point where you can try it out and see if it meets your requirements. Everything is up for discussion. If you can't use it either that's fine too.
Some questions i have:
But i do think this is a good start to get it moving out the door for merger.
too long to review every single line, but functioning ok, maybe we can have it at first, then optimize it little by little. I personally love and welcome new features added.
@cschuchardt88 do you mind to provide a readme for this plugin? i know others dont have it, but we will add readme for every plugin in the future. Mainly about what it is, what it does, how to use it, extra. basically what you have in the description of this pr
Merge since its a plugin, people dont install it if they dont like it.
@Liaojinghui, you're rushing too fast with this, IMO. People will install it, people will try building things on it. I'm not sure it's tested enough and stable enough for them to do that. And notice that it could've been a separate plugin for some time exactly for these experiments. Now it's an official plugin from the Neo project, people have higher expectations of those.
@roman-khimov I use it all the time. So It pretty stable. Its maybe lacking features. But all the basic and some advanced are all there.
@Liaojinghui, you're rushing too fast with this, IMO. People will install it, people will try building things on it. I'm not sure it's tested enough and stable enough for them to do that. And notice that it could've been a separate plugin for some time exactly for these experiments. Now it's an official plugin from the Neo project, people have higher expectations of those.
Agree and reverted (https://github.com/neo-project/neo-modules/commit/83372022c984c71ddbb2b0df64a83e16c6cfc1dc). Too many files without a deep review.
@Liaojinghui, you're rushing too fast with this, IMO. People will install it, people will try building things on it. I'm not sure it's tested enough and stable enough for them to do that. And notice that it could've been a separate plugin for some time exactly for these experiments. Now it's an official plugin from the Neo project, people have higher expectations of those.
Agree, but only if someone review it. I dont see how this can introduce more bugs than there has already be. I dont understand why you still stop merge and expect some one to review it while a pr has being there for 3 months and no one to review. I have checked the code and run it, no abvious issues found.
@roman-khimov I use it all the time. So It pretty stable. Its maybe lacking features. But all the basic and some advanced are all there.
Agree, but only if someone review it. I dont see how this can introduce more bugs than there has already be. I dont understand why you still stop merge and expect some one to review it while a pr has being there for 3 months and no one to review.
I understand, but understand that you have to review the code before merging, the more changes, the more complicated and time-consuming it requires, imagine (which I don't think is the case) that you add a line to leak the private key, all the code must be reviewed by at least two core developers, and tested by the great @superboyiii team.
Small pr will be reviewed faster than longer ones.
Yes, the same reason why so many prs stay there for many years without anyone care about them.
Yes, the same reason why so many prs stay there for many years without anyone care about them.
The solution is not merge all of them.
@cschuchardt88 please open a new PR with these changes.
Not all of them, but something i have reviewed, and no one else review it after months. We can wait, but should not be endless waiting.
That's why roadmaps and plans matter. Set some target, like "this PR should be dealt with by this time" and work towards that goal. Not planned? Likely not critical for now then (sure, life is complicated and sometimes it is). Add it to some milestone in the future, but keep real concentration on the nearest goals. We can't solve all problems at once and we can't risk destabilizing the system by accepting everything without proper reviews and tests. Going one problem after another with intermediate stable releases is more viable.
Adding Restful services to Neo N3 ecosystem. This uses
MVC
model without the view aspect. I currently don't know how much easier I can make this plugin. When it comes to flexibility and freedom. This system was design with usability. To allow the freedom of making what you want with plugins and will have a fault tolerant model. Also this model can allow upgrades, if Neo ever decides to makeneo-cli
have a built in webserver that handlesRPC
,Rest
,WSS
; this would be the code to do so. The already built plugins that are using this RestServer Plugin would not need to be changed.This plugin is
test
ready. I'm not trying to rush it and understand it takes a lot of time. But I would love some feedback on this plugin. If you decide to not use this plugin. By all means this plugin will not end here.The goal here is to have its client be dependency free of the
Neo.dll
and all its dependencies. Of course you can still add them if need be. LikeNeo.vm.dll
for building scripts to send viaRest
service call. I want to have this client and this plugins endpoints be available in other parts of thedotnet
ecosystem. Just to name a fewMono.Net
,.NET Maui
andUnity
. This will help the Neo user base have no limitations on whatever framework or technology they desire to use.As for maintainability, I'm not going anywhere; anytime soon and I have tons of time on my hands to write document, answer questions and update code. You have to start somewhere; so let's come together!
Yes I know it seemed fast; for me to make this plugin, But I really started at the begin of the year working on it and learning the neo-cli. 😸 So this is 5 months worth of learning and reading source code. 3 months of programming the code. My background is architecture design of systems.
See https://github.com/neo-project/neo/issues/1004
Documentation
This RestServer Documentation explains the working of the
RestServer
plugin. Note still a work in progress.RestServer Addon Plugins This Example Plugin Documentation explains how to make plugins for the
RestServer
.Downloads
Swagger UI
RestClient Code Example
Key Features
Change Log
Testing Progress
Neo-Cli Commands
You can just add Swagger OpenAPI 2.0 to any project by
Step1
Step 2
Step 3