Closed iBicha closed 1 year ago
@wing328 Here's my take on a Unity C# generator
@iBicha thanks for sharing your feedback. I've copied the C# technical committee below:
cc @mandrean (2017/08) @jimschubert (2017/09)
What's stopping you from using the unity editor integrated JSON utility? Code generation will never run at runtime. I think that's better than introducing a new dependency (aka newtonsoft)
That's a good question. Just to clarify, the JSON deserialization will run at runtime during api calls. But the reason the json utility probably not the best suited is because it's very limited when it comes to supported types.
@iBicha have you taken a look at the refactor work you've linked? I'm wondering if the API abstractions I've made would support the UnityWebRequest
cleanly.
The intention of the refactor is that it allows users to write their own simple adaptors for api query operations such that you can have a task-based asynchronous client or a synchronous client. The API implementation types then allow you to set these client instances directly.
So, for example, you could create a file, UnityAsyncClient
:
class UnityAsyncClient : IAsynchronousClient {
public Task<ApiResponse<T>> GetAsync<T>(String path, RequestOptions options, IReadableConfiguration configuration = null) {
var config = configuration ?? GlobalConfiguration.Instance;
using (UnityWebRequest www = UnityWebRequest.Get(config.BasePath + path))
{
var query = www.Send();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
// Show results as text
Debug.Log(www.downloadHandler.text);
// Or retrieve results as binary data
byte[] results = www.downloadHandler.data;
// await + construct ApiResponse<T>
}
}
}
// etc.
}
Then, you could construct APIs:
var api = new PetApi(){
AsynchronousClient = new UnityAsyncClient(),
SynchronousClient = null // or other implementation
}
I haven't worked with Unity, and their docs look pretty light, so the above is just a copy/paste from their example code.
Sorry it's taking me a while to respond. I've been meaning to respond with proper feedback for some time now but I didn't get the time around it. Will do asap
I've been working on Unity friendly OpenAPI parser and assets generator for some time, it resolves all issues with the multi-platform support and leverage many Unity specific tools to provide an easiest possible way to work with restful API
Maybe we can leverage https://github.com/proyecto26/RestClient instead of using RestSharp.
this feels like a duplicate of #6800 in some ways, AFAIK the biggest blocker to using any of the current generators in a unity project is the use of restsharp
@nk2580 have you considered the suggestion by @jimschubert: https://github.com/OpenAPITools/openapi-generator/issues/853#issuecomment-417163199 ?
@wing328 when it’s not a part of a unity package that works fine. When considering a unity package it’s a pretty big issue to rely upon restsharp when there’s no official package for it.
@nk2580 ok. What would you suggest to replace RestSharp?
My previous suggestion: https://github.com/OpenAPITools/openapi-generator/issues/853#issuecomment-477476526
IMO using vanilla net.http is going to be the best and most compatible solution for unity and dotnet
We've added a new library option httpclient
(e.g. in CLI --library httpclient
) to the csharp-netcore client generator. Please pull the latest master or using the SNAPSHOT version to give it a try and let us know if you've any feedback
The library option helps getting rid of RestSharp, but is there a way to disable the use of classes in System.ComponentModel.DataAnnotations
(IValidationContext
and other) ? This dll is not available in unity per default as well.
@nstdspace You can add a define in csc.rsp
with -r:System.ComponentModel.DataAnnotations.dll
, that works for us (using RestSharp, but I don't think that should change the fix)
Edit: you must use .Net Framework
and not .Net Standard
I would add to this conversation that relying on the built-in C# APIs or Restsharp will bite you hard when you need to ship on two of the three major consoles.
UnityWebRequest
integrates with custom logic on these consoles to use their platform libraries:
UnityWebRequest
doesn't support access to the platform's SSL certificate store. You have to embed certificates at build time and apply for a special waiver to use them. This then becomes a ticking time bomb because your root certs can expire while your game is in the wild.UnityWebRequest
since it integrates natively with the platform's custom version of libcurl.I am in the process of writing a modified C# code generator implementation that uses UnityWebRequest
. Unfortunately I doubt I can make a PR for this because 1) it won't hook into a unit test framework, 2) the odds of it being approved in this project seem low with 380 pending PRs, 3) adding a new library choice to the csharp-netcore
is very limiting because there are other poor design choices that are untenable (such as a complete lack of notification of connection errors or assumption that a response will always be JSON) and 4) it might require NDA console-specific code.
I put up a PR containing a working implementation of a UnityWebRequest
csharp-netcore library plugin:
https://github.com/OpenAPITools/openapi-generator/pull/13890
@bawahakim
You can add a define in
csc.rsp
withr:System.ComponentModel.DataAnnotations.dll
Could you help me understand what this means? I've tried putting this into my Player Settings "additional compiler arguments" but it says error CS0006: Metadata file 'System.ComponentModel.DataAnnotations.dll' could not be found
Copying from /Library/Mono.framework doesn't seem to be a fix (Invalid
@wing328 First party documentation on how to bootstrap a Unity compatible client would be enormously helpful. Especially with the httpclient
option this feels very close to being a godsend for the millions of indie game devs who want to utilize REST clients.
EDIT: FWIW, I'm using MacOS, and my understanding is that DataAnotations is generally less available for MacOS. I wonder if this could be avoided as a dependency to improve cross platform compatibility?
@pixelpax You just need to create a file anywhere in your Assets
folder called csc.rsp
, and add the line r:System.ComponentModel.DataAnnotations.dll
inside the file. We also develop and build for Mac and never had any issue with DataAnnotations
, as long as we're using .net Framework
Also, we switched to Nswag which supports using our own implementation of the HTTP client (we use UnityWebRequest), which makes things very smooth and compatible across all platforms: https://github.com/RicoSuter/NSwag/issues/2608#issuecomment-1294728900
The migration for us was relatively simple :)
@bawahakim Can't thank you enough for pointing me in the right direction here.
To summarize for anyone finding this thread while trying to build a generated Unity client circa early 2023:
openapi-generator generate -i swagger/v1/swagger.yaml -o ../path/to/generatedClient -g csharp-netcore --library httpclient
/Assets/csc.rsp
with the contents -r:System.ComponentModel.DataAnnotations.dll
Sincerely thanks for giving back to the community on this @bawahakim, I'm not very experienced with the nitty gritty of C# compilation, as is probably the case with many indie game devs, so thank you for breaking this down and giving back to the community :)
To the maintainers: @mandrean @jimschubert , an option to inject our own HttpClient implementation based on some IHttpClient interface would be a great convenience here so that those of us using Unity can make this part of our build pipeline instead of having to patch generated code. A default option to use UnityWebRequest would be even better :D
@pixelpax you are most welcome! Your encouragements pushed me to publish an article on medium, with a bit more details :D
https://medium.com/@bawahakim/generated-api-client-for-unity-in-c-with-unitywebrequest-78c8418228ba
Thanks a lot for the effort everyone, I'm also trying to implement this. I'll try with @bawahakim solution using NSwag as adding NuGet dlls (like Polly) to Unity is probematic when trying to build for WebGL and other IL2CPP platforms.
Hi @bawahakim. I followed your Medium article (amazing, thanks!) but I can't get it to work for WebGL. Encountering this issue when executing a request:
Have you encountered something similar?
Thanks!
Hi everyone, can you please also review the following PR to support UnityWebRequest in csharp-netcore
client generato?
https://github.com/OpenAPITools/openapi-generator/pull/13890
Hi @bawahakim. I followed your Medium article (amazing, thanks!) but I can't get it to work for WebGL. Encountering this issue when executing a request:
Have you encountered something similar?
Thanks!
@dpradell-moralis Ah yes, I've updated the method CreateHttpResponseMessage
, please give this a go and let me know if it works.
@bawahakim thanks for that. I removed the GetResponseHeaders()
part and it worked already but I'll try your solution. Thanks!
Description
This is an issue to discuss how a C# generator can be effectively useful in a Unity project. I've been told the C# codegen is under a refactor phase, so my suggestion is to consider the next few points, to maybe include in this refactor.
I don't know if Unity will require a separate template, but it's a possibility.
Related issues/PRs
This issue will extend the points discussed here, kindly consider taking a look at it before continuing: https://github.com/swagger-api/swagger-codegen/issues/8569
Suggest a fix/enhancement
Here's a list of things one might want to consider when supporting codegen for Unity:
Note that the response is returned on the main thread (and of course, the deserialization of the response should happen on a background thread).
Also, this can easily be made into an
async/await
style by creating an Awaiter, maybe something like this:Which will bring me to the next point:
As for Json serialization, the obvious choice would be Newtonsoft's, although it is known that there are few modifications needed for it to work correctly on different platforms. This asset could be of help.
The
IL2CPP
backend converts C# code into C++, for performance purposes. While this is a great feature, it has few limitations, including working with generic virtual methods (see the bottom of the page). In one of the cases (as an example), the deserialization fails because the converter tries to construct aCollectionWrapper<decimal?>
object, which was not generated. So what I had to do is to make a call to it somewhere, so the the IL2CPP backend would pick it up, and generate the C++ equivalent:Once the constructor is actually called anywhere in the code, the code converter picks it up and generate equivalent C++ code for it.
Note 1: When il2cpp backend is used, the symbol
ENABLE_IL2CPP
is defined. Note 2: in this case,CollectionWrapper
is internal, that's why I had to make it public, and recompile the Json.Net library. For this reason, any method generic virtual method needed for the correct deserialization can be generated accordingly, as needed (a work around for private/internal types might be needed)Script compilation and assembly definition files Unity recompiles the project after every code change automatically. Assembly definition files can divide code into separate assemblies/projects, for faster compilation. An OpenAPI generated project can have it's own probably.
In my previous issue, I mention editor extensions to make it easier to generate code. This can be a separate project which makes a call to the C# generator (either through a CLI or a rest service). This is something I have implemented with the current C# generator of swagger, and it helped me iterate faster (after changing a json file containing my spec, I can regenerate the code with a click of a button, see image from previous issue)
Unity mostly doesn't need any build scripts, only raw C# files.
Supporting Unity Test Runner
Please feel free to ask questions, and discuss. But from my experience with codegen and Unity, these are the main points that would make working with REST APIs a seamless experience when using Unity.