Skip to content

Commit

Permalink
Implemented Promise requests using PromiseYielder instead of Corout…
Browse files Browse the repository at this point in the history
…ines.

Replaced RSG with ProtoPromise in demo.
Updated readme.
  • Loading branch information
timcassell committed May 18, 2023
1 parent 14af97e commit ccfcb12
Show file tree
Hide file tree
Showing 28 changed files with 9,043 additions and 255 deletions.
60 changes: 34 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,22 @@ RestClient.GetArray<Post>(api + "/posts", (err, res) => {
But working with **Promises** we can improve our code, yay! 👏

```csharp
RestClient.GetArray<Post>(api + "/posts").Then(response => {
EditorUtility.DisplayDialog ("Success", JsonHelper.ArrayToJson<Post>(response, true), "Ok");
return RestClient.GetArray<Todo>(api + "/todos");
}).Then(response => {
EditorUtility.DisplayDialog ("Success", JsonHelper.ArrayToJson<Todo>(response, true), "Ok");
return RestClient.GetArray<User>(api + "/users");
}).Then(response => {
EditorUtility.DisplayDialog ("Success", JsonHelper.ArrayToJson<User>(response, true), "Ok");
}).Catch(err => EditorUtility.DisplayDialog ("Error", err.Message, "Ok"));
RestClient.GetArray<Post>(api + "/posts")
.Then(response =>
{
EditorUtility.DisplayDialog ("Success", JsonHelper.ArrayToJson<Post>(response, true), "Ok");
return RestClient.GetArray<Todo>(api + "/todos");
})
.Then(response =>
{
EditorUtility.DisplayDialog ("Success", JsonHelper.ArrayToJson<Todo>(response, true), "Ok");
return RestClient.GetArray<User>(api + "/users");
})
.Then(response => {
EditorUtility.DisplayDialog ("Success", JsonHelper.ArrayToJson<User>(response, true), "Ok");
})
.Catch((RequestException err) => EditorUtility.DisplayDialog ("Error", err.Message, "Ok"))
.Forget();
```

## Features 🎮
Expand All @@ -51,7 +58,7 @@ RestClient.GetArray<Post>(api + "/posts").Then(response => {
- Automatic transforms for **JSON Arrays**.
- Supports default **HTTP** Methods **(GET, POST, PUT, DELETE, HEAD, PATCH)**
- Generic **REQUEST** method to create any http request
- Based on **Promises** for a better asynchronous programming. Learn about Promises [here](https://github.com/Real-Serious-Games/C-Sharp-Promise)!
- Based on **Promises** for a better asynchronous programming. Learn about Promises [here](https://github.com/timcassell/ProtoPromise)!
- Utility to work during scene transition
- Handle HTTP exceptions and retry requests easily
- Open Source 🦄
Expand Down Expand Up @@ -80,7 +87,7 @@ Do you want to see this beautiful package in action? Download the demo [here](ht
Download and install the **.unitypackage** file of the latest release published [here](https://github.com/proyecto26/RestClient/releases).

### UPM package
Make sure you had installed [C# Promise package](https://openupm.com/packages/com.rsg.promise/) or at least have it in your [openupm scope registry](https://openupm.com/). Then install **RestClient package** using this URL from **Package Manager**: `https://github.com/proyecto26/RestClient.git#upm`
Make sure you had installed [ProtoPromise package](https://openupm.com/packages/com.timcassell.protopromise/) or at least have it in your [openupm scope registry](https://openupm.com/). Then install **RestClient package** using this URL from **Package Manager**: `https://github.com/proyecto26/RestClient.git#upm`

### NuGet package
Other option is download this package from **NuGet** with **Visual Studio** or using the **nuget-cli**, a **[NuGet.config](https://github.com/proyecto26/RestClient/blob/master/demo/NuGet.config)** file is required at the root of your **Unity Project**, for example:
Expand All @@ -100,19 +107,19 @@ The default methods **(GET, POST, PUT, DELETE, HEAD)** are:
```csharp
RestClient.Get("https://jsonplaceholder.typicode.com/posts/1").Then(response => {
EditorUtility.DisplayDialog("Response", response.Text, "Ok");
});
}).Forget();
RestClient.Post("https://jsonplaceholder.typicode.com/posts", newPost).Then(response => {
EditorUtility.DisplayDialog("Status", response.StatusCode.ToString(), "Ok");
});
}).Forget();
RestClient.Put("https://jsonplaceholder.typicode.com/posts/1", updatedPost).Then(response => {
EditorUtility.DisplayDialog("Status", response.StatusCode.ToString(), "Ok");
});
}).Forget();
RestClient.Delete("https://jsonplaceholder.typicode.com/posts/1").Then(response => {
EditorUtility.DisplayDialog("Status", response.StatusCode.ToString(), "Ok");
});
}).Forget();
RestClient.Head("https://jsonplaceholder.typicode.com/posts").Then(response => {
EditorUtility.DisplayDialog("Status", response.StatusCode.ToString(), "Ok");
});
}).Forget();
```

## Handling during scene transition
Expand Down Expand Up @@ -164,10 +171,10 @@ RestClient.Request(new RequestHelper {
AssetBundle assetBundle = ((DownloadHandlerAssetBundle)response.Request.downloadHandler).assetBundle;

EditorUtility.DisplayDialog("Status", response.StatusCode.ToString(), "Ok");
}).Catch(err => {
}).Catch((RequestException err) => {
var error = err as RequestException;
EditorUtility.DisplayDialog("Error Response", error.Response, "Ok");
});
}).Forget();
```

- Example downloading an audio file:
Expand All @@ -182,9 +189,9 @@ RestClient.Get(new RequestHelper {
AudioSource audio = GetComponent<AudioSource>();
audio.clip = ((DownloadHandlerAudioClip)res.Request.downloadHandler).audioClip;
audio.Play();
}).Catch(err => {
}).Catch((RequestException err) => {
EditorUtility.DisplayDialog ("Error", err.Message, "Ok");
});
}).Forget();
```

With all the methods we have the possibility to indicate the type of response, in the following example we're going to create a class and the **HTTP** requests to load **JSON** data easily:
Expand All @@ -206,13 +213,13 @@ public class User
var usersRoute = "https://jsonplaceholder.typicode.com/users";
RestClient.Get<User>(usersRoute + "/1").Then(firstUser => {
EditorUtility.DisplayDialog("JSON", JsonUtility.ToJson(firstUser, true), "Ok");
});
}).Forget();
```
* **GET Array (JsonHelper is an extension to manage arrays)**
```csharp
RestClient.GetArray<User>(usersRoute).Then(allUsers => {
EditorUtility.DisplayDialog("JSON Array", JsonHelper.ArrayToJsonString<User>(allUsers, true), "Ok");
});
}).Forget();
```

Also we can create different classes for custom responses:
Expand All @@ -227,13 +234,13 @@ public class CustomResponse
```csharp
RestClient.Post<CustomResponse>(usersRoute, newUser).Then(customResponse => {
EditorUtility.DisplayDialog("JSON", JsonUtility.ToJson(customResponse, true), "Ok");
});
}).Forget();
```
* **PUT**
```csharp
RestClient.Put<CustomResponse>(usersRoute + "/1", updatedUser).Then(customResponse => {
EditorUtility.DisplayDialog("JSON", JsonUtility.ToJson(customResponse, true), "Ok");
});
}).Forget();
```

## Custom HTTP Headers, Params and Options 💥
Expand All @@ -260,7 +267,7 @@ var currentRequest = new RequestHelper {
};
RestClient.GetArray<Photo>(currentRequest).Then(response => {
EditorUtility.DisplayDialog("Header", currentRequest.GetHeader("Authorization"), "Ok");
});
}).Forget();
```

And we can know the status of the request and cancel it!
Expand Down Expand Up @@ -305,7 +312,7 @@ RestClient.Post<ServerResponse>("www.api.com/endpoint", new User {
}).Then(response => {
EditorUtility.DisplayDialog("ID: ", response.id, "Ok");
EditorUtility.DisplayDialog("Date: ", response.date, "Ok");
});
}).Forget();
```
- NodeJS as Backend (Using [Express](http://expressjs.com/es/starter/hello-world.html))
```js
Expand All @@ -319,6 +326,7 @@ router.post('/', function(req, res) {
```

## Credits 👍
* **ProtoPromise** [Robust and efficient library for management of asynchronous operations.](https://github.com/timcassell/ProtoPromise)
* **C-Sharp-Promise:** [Promises library for C# for management of asynchronous operations.](https://github.com/Real-Serious-Games/C-Sharp-Promise)
* **MyAPI:** [A template to create awesome APIs easily ⚡️](https://github.com/proyecto26/MyAPI)

Expand Down
178 changes: 101 additions & 77 deletions demo/Assets/MainScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,96 +4,120 @@
using Proyecto26;
using System.Collections.Generic;

public class MainScript : MonoBehaviour {
public class MainScript : MonoBehaviour
{
private readonly string basePath = "https://jsonplaceholder.typicode.com";

private readonly string basePath = "https://jsonplaceholder.typicode.com";

private void LogMessage(string title, string message) {
private void LogMessage(string title, string message)
{
#if UNITY_EDITOR
EditorUtility.DisplayDialog (title, message, "Ok");
EditorUtility.DisplayDialog(title, message, "Ok");
#else
Debug.Log(message);
#endif
}

public void Get(){

// We can add default request headers for all requests
RestClient.DefaultRequestHeaders["Authorization"] = "Bearer ...";
}

RequestHelper requestOptions = null;
public void Get()
{
// We can add default request headers for all requests
RestClient.DefaultRequestHeaders["Authorization"] = "Bearer ...";

RestClient.GetArray<Post>(basePath + "/posts").Then(res => {
this.LogMessage ("Posts", JsonHelper.ArrayToJsonString<Post>(res, true));
return RestClient.GetArray<Todo>(basePath + "/todos");
}).Then(res => {
this.LogMessage ("Todos", JsonHelper.ArrayToJsonString<Todo>(res, true));
return RestClient.GetArray<User>(basePath + "/users");
}).Then(res => {
this.LogMessage ("Users", JsonHelper.ArrayToJsonString<User>(res, true));
RequestHelper requestOptions = null;

// We can add specific options and override default headers for a request
requestOptions = new RequestHelper {
Uri = basePath + "/photos",
EnableDebug = true,
Headers = new Dictionary<string, string> {
{ "Authorization", "Other token..." }
}
};
return RestClient.GetArray<Photo>(requestOptions);
}).Then(res => {
this.LogMessage("Header", requestOptions.GetHeader("Authorization"));
RestClient.GetArray<Post>(basePath + "/posts")
.Then(res =>
{
this.LogMessage("Posts", JsonHelper.ArrayToJsonString<Post>(res, true));
return RestClient.GetArray<Todo>(basePath + "/todos");
})
.Then(res =>
{
this.LogMessage("Todos", JsonHelper.ArrayToJsonString<Todo>(res, true));
return RestClient.GetArray<User>(basePath + "/users");
})
.Then(res =>
{
this.LogMessage("Users", JsonHelper.ArrayToJsonString<User>(res, true));
// And later we can clean the default headers for all requests
RestClient.ClearDefaultHeaders();
// We can add specific options and override default headers for a request
requestOptions = new RequestHelper
{
Uri = basePath + "/photos",
EnableDebug = true,
Headers = new Dictionary<string, string> {
{ "Authorization", "Other token..." }
}
};
return RestClient.GetArray<Photo>(requestOptions);
})
.Then(res =>
{
this.LogMessage("Header", requestOptions.GetHeader("Authorization"));
}).Catch(err => this.LogMessage ("Error", err.Message));
}
// And later we can clean the default headers for all requests
RestClient.ClearDefaultHeaders();
public void Post(){

RestClient.Post<Post>(basePath + "/posts", new Post {
title = "My first title",
body = "My first message",
userId = 26
})
.Then(res => this.LogMessage ("Success", JsonUtility.ToJson(res, true)))
.Catch(err => this.LogMessage ("Error", err.Message));
}
})
.Catch((RequestException err) => this.LogMessage("Error", err.Message))
.Forget();
}

public void Put(){
public void Post()
{
RestClient.Post<Post>(basePath + "/posts", new Post
{
title = "My first title",
body = "My first message",
userId = 26
})
.Then(res => this.LogMessage("Success", JsonUtility.ToJson(res, true)))
.Catch((RequestException err) => this.LogMessage("Error", err.Message))
.Forget();
}

RestClient.Put<Post>(new RequestHelper {
Uri = basePath + "/posts/1",
Body = new Post {
title = "My new title",
body = "My new message",
userId = 26
},
Retries = 5,
RetrySecondsDelay = 1,
RetryCallback = (err, retries) => {
Debug.Log(string.Format("Retry #{0} Status {1}\nError: {2}", retries, err.StatusCode, err));
}
}, (err, res, body) => {
if(err != null){
this.LogMessage ("Error", err.Message);
}
else{
this.LogMessage ("Success", res.Text);
}
});
}
public void Put()
{
RestClient.Put<Post>(new RequestHelper
{
Uri = basePath + "/posts/1",
Body = new Post
{
title = "My new title",
body = "My new message",
userId = 26
},
Retries = 5,
RetrySecondsDelay = 1,
RetryCallback = (err, retries) =>
{
Debug.Log(string.Format("Retry #{0} Status {1}\nError: {2}", retries, err.StatusCode, err));
}
}, (err, res, body) =>
{
if (err != null)
{
this.LogMessage("Error", err.Message);
}
else
{
this.LogMessage("Success", res.Text);
}
});
}

public void Delete(){
public void Delete()
{

RestClient.Delete(basePath + "/posts/1", (err, res) => {
if(err != null){
this.LogMessage ("Error", err.Message);
}
else{
this.LogMessage ("Success", "Status: " + res.StatusCode.ToString());
}
});
}
RestClient.Delete(basePath + "/posts/1", (err, res) =>
{
if (err != null)
{
this.LogMessage("Error", err.Message);
}
else
{
this.LogMessage("Success", "Status: " + res.StatusCode.ToString());
}
});
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit ccfcb12

Please sign in to comment.