├── Scripts ├── Service │ ├── Unity │ │ ├── IUpdateProgress.cs │ │ ├── IUpdateProgress.cs.meta │ │ ├── UnityHttpService.cs.meta │ │ ├── UnityHttpRequest.cs.meta │ │ ├── UnityHttpRequest.cs │ │ └── UnityHttpService.cs │ ├── Unity.meta │ ├── HttpResponse.cs.meta │ ├── IHttpRequest.cs.meta │ ├── IHttpService.cs.meta │ ├── HttpResponse.cs │ ├── IHttpRequest.cs │ └── IHttpService.cs ├── Duck.Http.asmdef ├── Duck.Http.asmdef.meta ├── Service.meta ├── Http.cs.meta ├── HttpUtils.cs.meta ├── HttpUtils.cs └── Http.cs ├── package.json.meta ├── Scripts.meta ├── Tests.meta ├── Tests ├── EditMode.meta ├── PlayMode.meta ├── EditMode │ ├── Duck.Http.Tests.EditMode.asmdef.meta │ ├── UtilsTests.cs.meta │ ├── Duck.Http.Tests.EditMode.asmdef │ └── UtilsTests.cs └── PlayMode │ ├── Duck.Http.Tests.PlayMode.asmdef.meta │ ├── HttpTests.cs.meta │ ├── Duck.Http.Tests.PlayMode.asmdef │ └── HttpTests.cs ├── LICENSE.md.meta ├── README.md.meta ├── package.json ├── LICENSE.md └── README.md /Scripts/Service/Unity/IUpdateProgress.cs: -------------------------------------------------------------------------------- 1 | namespace Duck.Http.Service.Unity 2 | { 3 | public interface IUpdateProgress 4 | { 5 | void UpdateProgress(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe01c499afe0c1e448ad84a40795f482 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1cb12764f087147ce90169fbf841d98c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e60d6e685c9345b58c9b0191c9042c1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Duck.Http.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Duck.Http", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false 8 | } -------------------------------------------------------------------------------- /Scripts/Duck.Http.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 234ae69a98d734645952bb4c0be67d86 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests/EditMode.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6966dec3b40d4bcea21b5488526ceaa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/PlayMode.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f83fd03dcf46e41a3a3456eeb7d0c53f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Service.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfd047a3f59734a51a1a8499279e1515 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Scripts/Service/Unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4f575aae9af66409482a7d85dcbb4c4c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Tests/EditMode/Duck.Http.Tests.EditMode.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bc5895155a714405294eebf9456e0082 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Tests/PlayMode/Duck.Http.Tests.PlayMode.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 229c94225b0194ca2a5b97faa2cd53f4 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dd2ce64b17f2a4007bebee899b69a51d 3 | timeCreated: 1527771002 4 | licenseType: Pro 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 101296658b41e44ba8bfff29a369d31e 3 | timeCreated: 1527771002 4 | licenseType: Pro 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Tests/EditMode/UtilsTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d75da1a6af72c494fafb26fae5f45494 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/PlayMode/HttpTests.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 477e8d825243547788f6acfd13d56a17 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/Service/HttpResponse.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6c4fc3727a00d4faea5dc1e0e4e27c90 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/Service/IHttpRequest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: efbb9a68bed7d48119e7a62f21665bd2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/Service/IHttpService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70e72137bb3c24eccb6f39e773a39a6f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Tests/PlayMode/Duck.Http.Tests.PlayMode.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Duck.Http.Tests.PlayMode", 3 | "references": [ 4 | "Duck.Http" 5 | ], 6 | "optionalUnityReferences": [ 7 | "TestAssemblies" 8 | ], 9 | "includePlatforms": [], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false 12 | } -------------------------------------------------------------------------------- /Scripts/Service/Unity/IUpdateProgress.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a285a89b7ed74632a349dde907c2fcf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Scripts/Service/Unity/UnityHttpService.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c796ec2d7a3534fde85334b9107d2c88 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.dubitlimited.duck.unity-http", 3 | "displayName": "Unity Http", 4 | "version": "2.2.1", 5 | "description": "An improved API for making http requests in unity", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/dubit/unity-http" 9 | }, 10 | "author": "Dubit Limited" 11 | } -------------------------------------------------------------------------------- /Scripts/Http.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 110f1e326ff89450999d230f523a715c 3 | timeCreated: 1513176759 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Scripts/HttpUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37efb1006aabf094daa1a081e6bf26e2 3 | timeCreated: 1513176759 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Tests/EditMode/Duck.Http.Tests.EditMode.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Duck.Http.EditMode.Tests", 3 | "references": [ 4 | "Duck.Http" 5 | ], 6 | "optionalUnityReferences": [ 7 | "TestAssemblies" 8 | ], 9 | "includePlatforms": [ 10 | "Editor" 11 | ], 12 | "excludePlatforms": [], 13 | "allowUnsafeCode": false 14 | } -------------------------------------------------------------------------------- /Scripts/Service/Unity/UnityHttpRequest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5952f3f94c4e34cbda7af88810c416bb 3 | timeCreated: 1513176759 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Scripts/Service/HttpResponse.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Duck.Http.Service 5 | { 6 | public class HttpResponse 7 | { 8 | public string Url { get; set; } 9 | public bool IsSuccessful { get; set; } 10 | public bool IsHttpError { get; set; } 11 | public bool IsNetworkError { get; set; } 12 | public long StatusCode { get; set; } 13 | public byte[] Bytes { get; set; } 14 | public string Text { get; set; } 15 | public string Error { get; set; } 16 | public Texture Texture { get; set; } 17 | public Dictionary ResponseHeaders { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Tests/EditMode/UtilsTests.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using NUnit.Framework; 3 | 4 | namespace Duck.Http.Tests.EditMode 5 | { 6 | [TestFixture] 7 | public class UtilsTests 8 | { 9 | [Test] 10 | public void Expect_Construct_Uri_From_Parameters() 11 | { 12 | const string URI = "https://subdomain.domain.extension/index.html"; 13 | const string EXPECTED_CONSTRUCTED_URI = URI + "?page=2&start=25&count=5"; 14 | var parameters = new Dictionary 15 | { 16 | {"page", "2"}, 17 | {"start", "25"}, 18 | {"count", "5"} 19 | }; 20 | var constructUriWithParameters = HttpUtils.ConstructUriWithParameters(URI, parameters); 21 | Assert.AreEqual(EXPECTED_CONSTRUCTED_URI, constructUriWithParameters); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Scripts/Service/IHttpRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Duck.Http.Service 5 | { 6 | public interface IHttpRequest 7 | { 8 | IHttpRequest RemoveSuperHeaders(); 9 | IHttpRequest SetHeader(string key, string value); 10 | IHttpRequest SetHeaders(IEnumerable> headers); 11 | IHttpRequest OnUploadProgress(Action onProgress); 12 | IHttpRequest OnDownloadProgress(Action onProgress); 13 | IHttpRequest OnSuccess(Action onSuccess); 14 | IHttpRequest OnError(Action onError); 15 | IHttpRequest OnNetworkError(Action onNetworkError); 16 | bool RemoveHeader(string key); 17 | IHttpRequest SetTimeout(int duration); 18 | IHttpRequest Send(); 19 | IHttpRequest SetRedirectLimit(int redirectLimit); 20 | void Abort(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/PlayMode/HttpTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using UnityEngine; 3 | 4 | namespace Duck.Http.Tests.PlayMode 5 | { 6 | [TestFixture] 7 | public class HttpTests 8 | { 9 | private Http http; 10 | 11 | [OneTimeSetUp] 12 | public void Setup() 13 | { 14 | http = Http.Instance; 15 | } 16 | 17 | [OneTimeTearDown] 18 | public void TearDown() 19 | { 20 | Object.DestroyImmediate(http.gameObject); 21 | } 22 | 23 | [Test] 24 | public void Expect_Singleton_Is_Created() 25 | { 26 | Assert.IsNotNull(http); 27 | } 28 | 29 | [Test] 30 | public void Expect_Set_Super_Headers() 31 | { 32 | const string HEADER_KEY = "HeaderKey"; 33 | const string HEADER_VALUE = "HeaderValue"; 34 | 35 | Http.SetSuperHeader(HEADER_KEY, HEADER_VALUE); 36 | var headers = Http.GetSuperHeaders(); 37 | 38 | Assert.IsTrue(headers.ContainsKey(HEADER_KEY)); 39 | Assert.AreEqual(HEADER_VALUE, headers[HEADER_KEY]); 40 | Assert.AreEqual(1, headers.Count); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2018 Dubit Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Scripts/HttpUtils.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text; 4 | 5 | namespace Duck.Http 6 | { 7 | /// 8 | /// A utility class for http. 9 | /// 10 | /// 11 | public static class HttpUtils 12 | { 13 | /// 14 | /// Format and append parameters to a uri 15 | /// 16 | /// The uri to append the properties to. 17 | /// A dictionary of parameters to append to the uri. 18 | /// The uri with the appended parameters. 19 | public static string ConstructUriWithParameters(string uri, Dictionary parameters) 20 | { 21 | if (parameters == null || parameters.Count == 0) 22 | { 23 | return uri; 24 | } 25 | 26 | var stringBuilder = new StringBuilder(uri); 27 | 28 | for (var i = 0; i < parameters.Count; i++) 29 | { 30 | var element = parameters.ElementAt(i); 31 | stringBuilder.Append(i == 0 ? "?" : "&"); 32 | stringBuilder.Append(element.Key); 33 | stringBuilder.Append("="); 34 | stringBuilder.Append(element.Value); 35 | } 36 | 37 | return stringBuilder.ToString(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Scripts/Service/Unity/UnityHttpRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine.Networking; 4 | 5 | namespace Duck.Http.Service.Unity 6 | { 7 | public class UnityHttpRequest : IHttpRequest, IUpdateProgress 8 | { 9 | internal UnityWebRequest UnityWebRequest => unityWebRequest; 10 | 11 | private readonly UnityWebRequest unityWebRequest; 12 | private readonly Dictionary headers; 13 | 14 | private event Action onUploadProgress; 15 | private event Action onDownloadProgress; 16 | private event Action onSuccess; 17 | private event Action onError; 18 | private event Action onNetworkError; 19 | 20 | private float downloadProgress; 21 | private float uploadProgress; 22 | 23 | public UnityHttpRequest(UnityWebRequest unityWebRequest) 24 | { 25 | this.unityWebRequest = unityWebRequest; 26 | headers = new Dictionary(Http.GetSuperHeaders()); 27 | } 28 | 29 | public IHttpRequest RemoveSuperHeaders() 30 | { 31 | foreach (var kvp in Http.GetSuperHeaders()) 32 | { 33 | headers.Remove(kvp.Key); 34 | } 35 | 36 | return this; 37 | } 38 | 39 | public IHttpRequest SetHeader(string key, string value) 40 | { 41 | headers[key] = value; 42 | return this; 43 | } 44 | 45 | public IHttpRequest SetHeaders(IEnumerable> headers) 46 | { 47 | foreach (var kvp in headers) 48 | { 49 | SetHeader(kvp.Key, kvp.Value); 50 | } 51 | 52 | return this; 53 | } 54 | 55 | public IHttpRequest OnUploadProgress(Action onProgress) 56 | { 57 | onUploadProgress += onProgress; 58 | return this; 59 | } 60 | 61 | public IHttpRequest OnDownloadProgress(Action onProgress) 62 | { 63 | onDownloadProgress += onProgress; 64 | return this; 65 | } 66 | 67 | public IHttpRequest OnSuccess(Action onSuccess) 68 | { 69 | this.onSuccess += onSuccess; 70 | return this; 71 | } 72 | 73 | public IHttpRequest OnError(Action onError) 74 | { 75 | this.onError += onError; 76 | return this; 77 | } 78 | 79 | public IHttpRequest OnNetworkError(Action onNetworkError) 80 | { 81 | this.onNetworkError += onNetworkError; 82 | return this; 83 | } 84 | 85 | public bool RemoveHeader(string key) 86 | { 87 | return headers.Remove(key); 88 | } 89 | 90 | public IHttpRequest SetTimeout(int duration) 91 | { 92 | unityWebRequest.timeout = duration; 93 | return this; 94 | } 95 | 96 | public IHttpRequest Send() 97 | { 98 | foreach (var header in headers) 99 | { 100 | unityWebRequest.SetRequestHeader(header.Key, header.Value); 101 | } 102 | 103 | Http.Instance.Send(this, onSuccess, onError, onNetworkError); 104 | return this; 105 | } 106 | 107 | public IHttpRequest SetRedirectLimit(int redirectLimit) 108 | { 109 | UnityWebRequest.redirectLimit = redirectLimit; 110 | return this; 111 | } 112 | 113 | public void UpdateProgress() 114 | { 115 | UpdateProgress(ref downloadProgress, unityWebRequest.downloadProgress, onDownloadProgress); 116 | UpdateProgress(ref uploadProgress, unityWebRequest.uploadProgress, onUploadProgress); 117 | } 118 | 119 | public void Abort() 120 | { 121 | Http.Instance.Abort(this); 122 | } 123 | 124 | private void UpdateProgress(ref float currentProgress, float progress, Action onProgress) 125 | { 126 | if (currentProgress < progress) 127 | { 128 | currentProgress = progress; 129 | onProgress?.Invoke(currentProgress); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Scripts/Service/Unity/UnityHttpService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using UnityEngine; 6 | using UnityEngine.Networking; 7 | 8 | namespace Duck.Http.Service.Unity 9 | { 10 | public class UnityHttpService : IHttpService 11 | { 12 | public IHttpRequest Get(string uri) 13 | { 14 | return new UnityHttpRequest(UnityWebRequest.Get(uri)); 15 | } 16 | 17 | public IHttpRequest GetTexture(string uri) 18 | { 19 | return new UnityHttpRequest(UnityWebRequestTexture.GetTexture(uri)); 20 | } 21 | 22 | public IHttpRequest Post(string uri, string postData) 23 | { 24 | return new UnityHttpRequest(UnityWebRequest.Post(uri, postData)); 25 | } 26 | 27 | public IHttpRequest Post(string uri, WWWForm formData) 28 | { 29 | return new UnityHttpRequest(UnityWebRequest.Post(uri, formData)); 30 | } 31 | 32 | public IHttpRequest Post(string uri, Dictionary formData) 33 | { 34 | return new UnityHttpRequest(UnityWebRequest.Post(uri, formData)); 35 | } 36 | 37 | public IHttpRequest Post(string uri, List multipartForm) 38 | { 39 | return new UnityHttpRequest(UnityWebRequest.Post(uri, multipartForm)); 40 | } 41 | 42 | public IHttpRequest Post(string uri, byte[] bytes, string contentType) 43 | { 44 | var unityWebRequest = new UnityWebRequest(uri, UnityWebRequest.kHttpVerbPOST) 45 | { 46 | uploadHandler = new UploadHandlerRaw(bytes) 47 | { 48 | contentType = contentType 49 | }, 50 | downloadHandler = new DownloadHandlerBuffer() 51 | }; 52 | return new UnityHttpRequest(unityWebRequest); 53 | } 54 | 55 | public IHttpRequest PostJson(string uri, string json) 56 | { 57 | return Post(uri, Encoding.UTF8.GetBytes(json), "application/json"); 58 | } 59 | 60 | public IHttpRequest PostJson(string uri, T payload) where T : class 61 | { 62 | return PostJson(uri, JsonUtility.ToJson(payload)); 63 | } 64 | 65 | public IHttpRequest Put(string uri, byte[] bodyData) 66 | { 67 | return new UnityHttpRequest(UnityWebRequest.Put(uri, bodyData)); 68 | } 69 | 70 | public IHttpRequest Put(string uri, string bodyData) 71 | { 72 | return new UnityHttpRequest(UnityWebRequest.Put(uri, bodyData)); 73 | } 74 | 75 | public IHttpRequest Delete(string uri) 76 | { 77 | return new UnityHttpRequest(UnityWebRequest.Delete(uri)); 78 | } 79 | 80 | public IHttpRequest Head(string uri) 81 | { 82 | return new UnityHttpRequest(UnityWebRequest.Head(uri)); 83 | } 84 | 85 | public IEnumerator Send(IHttpRequest request, Action onSuccess = null, 86 | Action onError = null, Action onNetworkError = null) 87 | { 88 | var unityHttpRequest = (UnityHttpRequest) request; 89 | var unityWebRequest = unityHttpRequest.UnityWebRequest; 90 | 91 | yield return unityWebRequest.SendWebRequest(); 92 | 93 | var response = CreateResponse(unityWebRequest); 94 | 95 | if (unityWebRequest.isNetworkError) 96 | { 97 | onNetworkError?.Invoke(response); 98 | } 99 | else if (unityWebRequest.isHttpError) 100 | { 101 | onError?.Invoke(response); 102 | } 103 | else 104 | { 105 | onSuccess?.Invoke(response); 106 | } 107 | } 108 | 109 | public void Abort(IHttpRequest request) 110 | { 111 | var unityHttpRequest = request as UnityHttpRequest; 112 | if (unityHttpRequest?.UnityWebRequest != null && !unityHttpRequest.UnityWebRequest.isDone) 113 | { 114 | unityHttpRequest.UnityWebRequest.Abort(); 115 | } 116 | } 117 | 118 | private static HttpResponse CreateResponse(UnityWebRequest unityWebRequest) 119 | { 120 | return new HttpResponse 121 | { 122 | Url = unityWebRequest.url, 123 | Bytes = unityWebRequest.downloadHandler?.data, 124 | Text = unityWebRequest.downloadHandler?.text, 125 | IsSuccessful = !unityWebRequest.isHttpError && !unityWebRequest.isNetworkError, 126 | IsHttpError = unityWebRequest.isHttpError, 127 | IsNetworkError = unityWebRequest.isNetworkError, 128 | Error = unityWebRequest.error, 129 | StatusCode = unityWebRequest.responseCode, 130 | ResponseHeaders = unityWebRequest.GetResponseHeaders(), 131 | Texture = (unityWebRequest.downloadHandler as DownloadHandlerTexture)?.texture 132 | }; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # unity-http 2 | 3 | ## What is it? 4 | The Http system has a quick and easy API for making http requests within Unity. 5 | The Http instance will run the WebRequest coroutines for you so you dont have to create it per request. 6 | 7 | ## Features 8 | * Singleton 9 | * Fluent API for configuration 10 | * Success, error and network error events 11 | * Super headers 12 | 13 | ## Requirements 14 | * Unity 2018.3+ 15 | * .NET 4.5 16 | * C# 7 17 | 18 | ## Installation 19 | 20 | Add it as a package using [Unity Package Manager](https://docs.unity3d.com/Manual/upm-git.html) or via submodule: 21 | `git submodule add git@github.com:dubit/unity-http.git Assets/Duck/Http` 22 | 23 | ## Releasing 24 | * Use [gitflow](https://nvie.com/posts/a-successful-git-branching-model/) 25 | * Create a release branch for the release 26 | * On that branch, bump version number in package json file, any other business (docs/readme updates) 27 | * Merge to master via pull request and tag the merge commit on master. 28 | * Merge back to development.# 29 | 30 | ## How to use it. 31 | If you are using an AssemblyDefinition then reference the Http Assembly. 32 | Import the namespace `using DUCK.Http;` 33 | 34 | ```c# 35 | var request = Http.Get("http://mywebapi.com/") 36 | .SetHeader("Authorization", "username:password") 37 | .OnSuccess(response => Debug.Log(response.Text)) 38 | .OnError(response => Debug.Log(response.StatusCode)) 39 | .OnDownloadProgress(progress => Debug.Log(progress)) 40 | .Send(); 41 | ``` 42 | 43 | ## API 44 | 45 | ### Http Static Methods 46 | 47 | All these methods return a new HttpRequest. 48 | 49 | ##### Get 50 | * `Http.Get(string uri)` 51 | * `Http.GetTexture(string uri)` 52 | ##### Post 53 | * `Http.Post(string uri, string postData)` 54 | * `Http.Post(string uri, WWWForm formData)` 55 | * `Http.Post(string uri, Dictionary formData))` 56 | * `Http.Post(string uri, List multipartForm)` 57 | * `Http.Post(string uri, byte[] bytes, string contentType)` 58 | ##### Post JSON 59 | * `Http.PostJson(string uri, string json)` 60 | * `Http.PostJson(string uri, T payload)` 61 | ##### Put 62 | * `Http.Put(string uri, byte[] bodyData)` 63 | * `Http.Put(string uri, string bodyData)` 64 | ##### Misc 65 | * `Http.Delete(string uri)` 66 | * `Http.Head(string uri)` 67 | 68 | ### Http Request Configuration Methods 69 | 70 | All these methods return the HttpRequest instance. 71 | ##### Headers 72 | * `SetHeader(string key, string value)` 73 | * `SetHeaders(IEnumerable> headers)` 74 | * `RemoveHeader(string key)` 75 | * `RemoveSuperHeaders()` 76 | ##### Events 77 | * `OnSuccess(Action response)` 78 | * `OnError(Action response)` 79 | * `OnNetworkError(Action response)` 80 | ##### Progress 81 | * `OnUploadProgress(Action progress)` 82 | * `OnDownloadProgress(Action progress)` 83 | ##### Configure 84 | * `SetRedirectLimit(int redirectLimit)` 85 | * `SetTimeout(int duration)` 86 | 87 | Redirect limit subject to Unity's documentation. 88 | * [Redirect Limit Documentation](https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest-redirectLimit.html) 89 | 90 | Progress events will invoke each time the progress value has increased, they are subject to Unity's documentation. 91 | * [Upload Progress Documentation](https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest-uploadProgress.html) 92 | * [Download Progress Documentation](https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest-downloadProgress.html) 93 | 94 | ### Http Request 95 | 96 | * `HttpRequest Send()` 97 | * `void Abort()` 98 | 99 | ### Http Response 100 | The callbacks for `OnSuccess`, `OnError` and `OnNetworkError` all return you a `HttpResponse`. 101 | This has the following properties: 102 | ##### Properties 103 | * `string Url` 104 | * `bool IsSuccessful` 105 | * `bool IsHttpError` 106 | * `bool IsNetworkError` 107 | * `long StatusCode` 108 | * `ResponseType ResponseType` 109 | * `byte[] Bytes` 110 | * `string Text` 111 | * `string Error` 112 | * `Texture Texture` 113 | * `Dictionary ResponseHeaders` 114 | 115 | ### Super Headers 116 | 117 | Super Headers are a type of Header that you can set once to automatically attach to every Request you’re sending. 118 | They are Headers that apply to all requests without having to manually include them in each HttpRequest SetHeader call. 119 | 120 | * `Http.SetSuperHeader(string key, string value)` 121 | * `Http.RemoveSuperHeader(string key)` returns `bool` 122 | * `Http.GetSuperHeaders()` returns `Dictionary` 123 | 124 | 125 | ## JSON Response Example 126 | In this given example, the `response.Text` from `http://mywebapi.com/user.json` is: 127 | ```json 128 | { 129 | "id": 92, 130 | "username": "jason" 131 | } 132 | ``` 133 | 134 | Create a serializable class that maps the data from the json response to fields 135 | ```c# 136 | [Serializable] 137 | public class User 138 | { 139 | [SerializeField] 140 | public int id; 141 | [SerializeField] 142 | public string username; 143 | } 144 | ``` 145 | 146 | We can listen for the event `OnSuccess` with our handler method `HandleSuccess` 147 | ```c# 148 | var request = Http.Get("http://mywebapi.com/user.json") 149 | .OnSuccess(HandleSuccess) 150 | .OnError(response => Debug.Log(response.StatusCode)) 151 | .Send(); 152 | ``` 153 | 154 | Parse the `response.Text` to the serialized class `User` that we declared earlier by using Unity's built in [JSONUtility](https://docs.unity3d.com/ScriptReference/JsonUtility.html) 155 | ```c# 156 | private void HandleSuccess(HttpResponse response) 157 | { 158 | var user = JsonUtility.FromJson(response.Text); 159 | Debug.Log(user.username); 160 | } 161 | ``` -------------------------------------------------------------------------------- /Scripts/Service/IHttpService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | using UnityEngine.Networking; 6 | 7 | namespace Duck.Http.Service 8 | { 9 | public interface IHttpService 10 | { 11 | /// 12 | /// Creates a HttpRequest configured for HTTP GET. 13 | /// 14 | /// The URI of the resource to retrieve via HTTP GET. 15 | /// A HttpRequest object configured to retrieve data from uri. 16 | IHttpRequest Get(string uri); 17 | 18 | /// 19 | /// Creates a HttpRequest configured for HTTP GET. 20 | /// 21 | /// The URI of the resource to retrieve via HTTP GET. 22 | /// A HttpRequest object configured to retrieve data from uri. 23 | IHttpRequest GetTexture(string uri); 24 | 25 | /// 26 | /// Creates a HttpRequest configured to send form data to a server via HTTP POST. 27 | /// 28 | /// The target URI to which form data will be transmitted. 29 | /// Form body data. Will be URLEncoded via WWWTranscoder.URLEncode prior to transmission. 30 | /// A HttpRequest configured to send form data to uri via POST. 31 | IHttpRequest Post(string uri, string postData); 32 | 33 | /// 34 | /// Creates a HttpRequest configured to send form data to a server via HTTP POST. 35 | /// 36 | /// The target URI to which form data will be transmitted. 37 | /// Form fields or files encapsulated in a WWWForm object, for formatting and transmission to the remote server. 38 | /// A HttpRequest configured to send form data to uri via POST. 39 | IHttpRequest Post(string uri, WWWForm formData); 40 | 41 | /// 42 | /// Creates a HttpRequest configured to send form data to a server via HTTP POST. 43 | /// 44 | /// The target URI to which form data will be transmitted. 45 | /// Form fields in the form of a Key Value Pair, for formatting and transmission to the remote server. 46 | /// A HttpRequest configured to send form data to uri via POST. 47 | IHttpRequest Post(string uri, Dictionary formData); 48 | 49 | /// 50 | /// Creates a HttpRequest configured to send form multipart form to a server via HTTP POST. 51 | /// 52 | /// The target URI to which form data will be transmitted. 53 | /// MultipartForm data for formatting and transmission to the remote server. 54 | /// A HttpRequest configured to send form data to uri via POST. 55 | IHttpRequest Post(string uri, List multipartForm); 56 | 57 | /// 58 | /// Creates a HttpRequest configured to send raw bytes to a server via HTTP POST. 59 | /// 60 | /// The target URI to which bytes will be transmitted. 61 | /// Byte array data. 62 | /// String representing the MIME type of the data (e.g. image/jpeg). 63 | /// A HttpRequest configured to send raw bytes to a server via POST. 64 | IHttpRequest Post(string uri, byte[] bytes, string contentType); 65 | 66 | /// 67 | /// Creates a HttpRequest configured to send json data to a server via HTTP POST. 68 | /// 69 | /// The target URI to which json data will be transmitted. 70 | /// Json body data. 71 | /// A HttpRequest configured to send json data to uri via POST. 72 | IHttpRequest PostJson(string uri, string json); 73 | 74 | /// 75 | /// Creates a HttpRequest configured to send json data to a server via HTTP POST. 76 | /// 77 | /// The target URI to which json data will be transmitted. 78 | /// The object to be parsed to json data. 79 | /// A HttpRequest configured to send json data to uri via POST. 80 | IHttpRequest PostJson(string uri, T payload) where T : class; 81 | 82 | /// 83 | /// Creates a HttpRequest configured to upload raw data to a remote server via HTTP PUT. 84 | /// 85 | /// The URI to which the data will be sent. 86 | /// The data to transmit to the remote server. 87 | /// A HttpRequest configured to transmit bodyData to uri via HTTP PUT. 88 | IHttpRequest Put(string uri, byte[] bodyData); 89 | 90 | /// 91 | /// Creates a HttpRequest configured to upload raw data to a remote server via HTTP PUT. 92 | /// 93 | /// The URI to which the data will be sent. 94 | /// The data to transmit to the remote server. 95 | /// The string will be converted to raw bytes via <a href="http:msdn.microsoft.comen-uslibrarysystem.text.encoding.utf8">System.Text.Encoding.UTF8<a>. 96 | /// A HttpRequest configured to transmit bodyData to uri via HTTP PUT. 97 | IHttpRequest Put(string uri, string bodyData); 98 | 99 | /// 100 | /// Creates a HttpRequest configured for HTTP DELETE. 101 | /// 102 | /// The URI to which a DELETE request should be sent. 103 | /// A HttpRequest configured to send an HTTP DELETE request. 104 | IHttpRequest Delete(string uri); 105 | 106 | /// 107 | /// Creates a HttpRequest configured to send a HTTP HEAD request. 108 | /// 109 | /// The URI to which to send a HTTP HEAD request. 110 | /// A HttpRequest configured to transmit a HTTP HEAD request. 111 | IHttpRequest Head(string uri); 112 | 113 | IEnumerator Send(IHttpRequest request, Action onSuccess = null, Action onError = null, Action onNetworkError = null); 114 | 115 | void Abort(IHttpRequest request); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Scripts/Http.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using Duck.Http.Service; 5 | using Duck.Http.Service.Unity; 6 | using UnityEngine; 7 | using UnityEngine.Networking; 8 | 9 | namespace Duck.Http 10 | { 11 | public sealed class Http : MonoBehaviour 12 | { 13 | public static Http Instance 14 | { 15 | get 16 | { 17 | if (instance != null) return instance; 18 | Init(new UnityHttpService()); 19 | return instance; 20 | } 21 | } 22 | 23 | private static Http instance; 24 | 25 | private IHttpService service; 26 | private Dictionary superHeaders; 27 | private Dictionary httpRequests; 28 | 29 | public static void Init(IHttpService service) 30 | { 31 | if (instance) return; 32 | 33 | instance = new GameObject(typeof(Http).Name).AddComponent(); 34 | instance.gameObject.hideFlags = HideFlags.HideInHierarchy; 35 | instance.superHeaders = new Dictionary(); 36 | instance.httpRequests = new Dictionary(); 37 | instance.service = service; 38 | DontDestroyOnLoad(instance.gameObject); 39 | } 40 | 41 | #region Super Headers 42 | 43 | /// 44 | /// Super headers are key value pairs that will be added to every subsequent HttpRequest. 45 | /// 46 | /// A dictionary of super-headers. 47 | public static Dictionary GetSuperHeaders() 48 | { 49 | return new Dictionary(Instance.superHeaders); 50 | } 51 | 52 | /// 53 | /// Sets a header to the SuperHeaders key value pair, if the header key already exists, the value will be replaced. 54 | /// 55 | /// The header key to be set. 56 | /// The header value to be assigned. 57 | public static void SetSuperHeader(string key, string value) 58 | { 59 | if (string.IsNullOrEmpty(key)) 60 | { 61 | throw new ArgumentException("Key cannot be null or empty."); 62 | } 63 | 64 | if (string.IsNullOrEmpty(value)) 65 | { 66 | throw new ArgumentException("Value cannot be null or empty, if you are intending to remove the value, use the RemoveSuperHeader() method."); 67 | } 68 | 69 | Instance.superHeaders[key] = value; 70 | } 71 | 72 | /// 73 | /// Removes a header from the SuperHeaders list. 74 | /// 75 | /// The header key to be removed. 76 | /// If the removal of the element was successful 77 | public static bool RemoveSuperHeader(string key) 78 | { 79 | if (string.IsNullOrEmpty(key)) 80 | { 81 | throw new ArgumentException("Key cannot be null or empty."); 82 | } 83 | 84 | return Instance.superHeaders.Remove(key); 85 | } 86 | 87 | #endregion 88 | 89 | #region Static Requests 90 | 91 | /// 92 | public static IHttpRequest Get(string uri) 93 | { 94 | return Instance.service.Get(uri); 95 | } 96 | 97 | /// 98 | public static IHttpRequest GetTexture(string uri) 99 | { 100 | return Instance.service.GetTexture(uri); 101 | } 102 | 103 | /// 104 | public static IHttpRequest Post(string uri, string postData) 105 | { 106 | return Instance.service.Post(uri, postData); 107 | } 108 | 109 | /// 110 | public static IHttpRequest Post(string uri, WWWForm formData) 111 | { 112 | return Instance.service.Post(uri, formData); 113 | } 114 | 115 | /// 116 | public static IHttpRequest Post(string uri, Dictionary formData) 117 | { 118 | return Instance.service.Post(uri, formData); 119 | } 120 | 121 | /// 122 | public static IHttpRequest Post(string uri, List multipartForm) 123 | { 124 | return Instance.service.Post(uri, multipartForm); 125 | } 126 | 127 | /// 128 | public static IHttpRequest Post(string uri, byte[] bytes, string contentType) 129 | { 130 | return Instance.service.Post(uri, bytes, contentType); 131 | } 132 | 133 | /// 134 | public static IHttpRequest PostJson(string uri, string json) 135 | { 136 | return Instance.service.PostJson(uri, json); 137 | } 138 | 139 | /// 140 | public static IHttpRequest PostJson(string uri, T payload) where T : class 141 | { 142 | return Instance.service.PostJson(uri, payload); 143 | } 144 | 145 | /// 146 | public static IHttpRequest Put(string uri, byte[] bodyData) 147 | { 148 | return Instance.service.Put(uri, bodyData); 149 | } 150 | 151 | /// 152 | public static IHttpRequest Put(string uri, string bodyData) 153 | { 154 | return Instance.service.Put(uri, bodyData); 155 | } 156 | 157 | /// 158 | public static IHttpRequest Delete(string uri) 159 | { 160 | return Instance.service.Delete(uri); 161 | } 162 | 163 | /// 164 | public static IHttpRequest Head(string uri) 165 | { 166 | return Instance.service.Head(uri); 167 | } 168 | 169 | #endregion 170 | 171 | internal void Send(IHttpRequest request, Action onSuccess = null, 172 | Action onError = null, Action onNetworkError = null) 173 | { 174 | var enumerator = SendCoroutine(request, onSuccess, onError, onNetworkError); 175 | var coroutine = StartCoroutine(enumerator); 176 | httpRequests.Add(request, coroutine); 177 | } 178 | 179 | private IEnumerator SendCoroutine(IHttpRequest request, Action onSuccess = null, 180 | Action onError = null, Action onNetworkError = null) 181 | { 182 | yield return service.Send(request, onSuccess, onError, onNetworkError); 183 | Instance.httpRequests.Remove(request); 184 | } 185 | 186 | internal void Abort(IHttpRequest request) 187 | { 188 | Instance.service.Abort(request); 189 | 190 | if (httpRequests.ContainsKey(request)) 191 | { 192 | StopCoroutine(httpRequests[request]); 193 | } 194 | 195 | Instance.httpRequests.Remove(request); 196 | } 197 | 198 | private void Update() 199 | { 200 | foreach (var httpRequest in httpRequests.Keys) 201 | { 202 | (httpRequest as IUpdateProgress)?.UpdateProgress(); 203 | } 204 | } 205 | } 206 | } 207 | --------------------------------------------------------------------------------