{"id":221,"date":"2017-01-29T21:40:19","date_gmt":"2017-01-30T02:40:19","guid":{"rendered":"http:\/\/naplandgames.com\/blog\/?p=221"},"modified":"2018-12-18T09:02:21","modified_gmt":"2018-12-18T14:02:21","slug":"data-serialization-part-2-unity3d-json-net-and-twitter-rest-api","status":"publish","type":"post","link":"https:\/\/naplandgames.com\/blog\/2017\/01\/29\/data-serialization-part-2-unity3d-json-net-and-twitter-rest-api\/","title":{"rendered":"Data Serialization Part 2 &#8211; Unity3D, Json.NET, and Twitter REST API"},"content":{"rendered":"<p>Why Json.NET? Unity does now include a Json utility, but it falls flat in many cases. It doesn&#8217;t serialize nested classes well (classes with multiple levels of inheritance), it can&#8217;t rename the Json object&#8217;s variables to something more appropriate for your code base, and there&#8217;s really not a lot of options. However, it does claim to be &#8220;&#8230;significantly faster than popular .NET JSON solutions&#8230;&#8221;. One of my favorite features of Json.NET is that it can easily serialize private fields and public fields with private setters. This allows for maintaining access restriction in you code base&#8217;s models without requiring the use of 2 objects: one that can serialize with public properties and another that is for use throughout the application with restricted public fields (or whatever custom logic you may need). You can even set up a constructor that the serializer is instructed to use. It&#8217;s quite powerful!<\/p>\n<p>This tutorial will show some basic usage of Json.NET to handle deserialization of Json responses from the Twitter API. You&#8217;ll be creating an app that can simply search Twitter statuses and then display them.<\/p>\n<blockquote><p><strong>Note:<\/strong>\u00a0This tutorial assumes you have at least a beginner&#8217;s knowledge of C# and Unity 3D. It will be helpful if you also have some experience with making HTTP requests, but not necessary as the requests in this tutorial are well defined.<\/p><\/blockquote>\n<figure id=\"attachment_223\" aria-describedby=\"caption-attachment-223\" style=\"width: 253px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/00_twitter_searcher.gif\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-223\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/00_twitter_searcher.gif\" alt=\"Twitter Search 1.0\" width=\"253\" height=\"445\" \/><\/a><figcaption id=\"caption-attachment-223\" class=\"wp-caption-text\">Twitter Search 1.0<\/figcaption><\/figure>\n<h2>Getting Started<\/h2>\n<p><a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/JsonAndTwitterStarterProject.zip\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #000000;\"><strong>You can download the stater project from here or follow along (there&#8217;s not a lot of steps in getting it all set up).<\/strong><\/span><\/a><\/p>\n<ol>\n<li>Create a new Unity 2D project and call it <strong>Twitter Searcher<\/strong>.<\/li>\n<li>Download Json.Net from here: <a href=\"https:\/\/github.com\/JamesNK\/Newtonsoft.Json\/releases\">github.com\/JamesNK\/Newtonsoft.Json\/releases<\/a>. You&#8217;ll want the release zip, not source code.<\/li>\n<li>In the zip there should be a folder called <strong>Bin<\/strong>. This is where all the DLLs live. Since Unity uses an implementation of .NET 3.5 you&#8217;ll want to select the library in the zip archive&#8217;s\u00a0<strong>Net35<\/strong> folder. Import <strong>Newtonsoft.Json.dll<\/strong> into a new Unity project in a folder called <strong>Plugins<\/strong>. You may also want to import the XML file as this contains documentation for the library, but you can also rely\u00a0on the website&#8217;s documentation found here\u00a0<a href=\"http:\/\/www.newtonsoft.com\/json\">www.newtonsoft.com\/json<\/a>.<\/li>\n<\/ol>\n<p>Now that the basics are imported you&#8217;ll also need to get access tokens to use Twitter&#8217;s API.<\/p>\n<ol>\n<li>Go to\u00a0<a href=\"https:\/\/dev.twitter.com\">dev.twitter.com<\/a> and sign up as a developer (there should be a <strong>Join<\/strong> button in the upper right corner of the screen). Fill out the necessary forms and follow their steps to complete the process.<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/01_twitter_dev_join.png\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-224\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/01_twitter_dev_join-300x56.png\" alt=\"01_twitter_dev_join\" width=\"300\" height=\"56\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/01_twitter_dev_join-300x56.png 300w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/01_twitter_dev_join-768x144.png 768w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/01_twitter_dev_join.png 931w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<li>Once you&#8217;ve completed Twitter&#8217;s verification process you&#8217;ll be able to to click on <strong>My Apps<\/strong> (should be at the top of the page) and then on the next page click on <strong>Create New App.<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/02_twitter_create_app.png\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-225\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/02_twitter_create_app-300x88.png\" alt=\"02_twitter_create_app\" width=\"300\" height=\"88\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/02_twitter_create_app-300x88.png 300w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/02_twitter_create_app-768x226.png 768w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/02_twitter_create_app.png 871w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/strong><\/li>\n<li>After creating your application you&#8217;ll need to get the Consumer API Key and the Consumer Secret. Under the\u00a0<strong>Application Settings\u00a0<\/strong>section you&#8217;ll see the Consumer Key and a link to\u00a0<strong>manage keys and access tokens<\/strong>. Click on that link.<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys1.png\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-227\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys1-300x78.png\" alt=\"03_twitter_keys1\" width=\"300\" height=\"78\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys1-300x78.png 300w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys1.png 687w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<li>On the next page you will see you\u00a0<strong>Consumer Key<\/strong> and\u00a0<strong>Consumer Secret<\/strong>. In the image below they&#8217;ve been blacked-out. Copy these keys into a text file.\u00a0<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys2.png\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-228\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys2-300x127.png\" alt=\"03_twitter_keys2\" width=\"300\" height=\"127\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys2-300x127.png 300w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/03_twitter_keys2.png 692w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/li>\n<\/ol>\n<h2>Making Twitter API Requests<\/h2>\n<p>The first class you&#8217;ll create is called <strong>TwitterSearchHandler<\/strong>. This will be responsible for getting authorization from Twitter and making the search request. The first task it will need to accomplish is connecting to Twitter and getting authorization via OAuth. Start the class like so:<\/p>\n<pre class=\"tab-convert:true lang:c# decode:true \" title=\"TwitterSearchHandler.cs\">using UnityEngine;\r\nusing System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\n\r\npublic class TwitterSearchHandler : MonoBehaviour\r\n{     \r\n    \/\/ 1 - The Consumer API Key you received from Twitter\r\n    private string apiKey = \"\";\r\n    \/\/ 2 - The Consumer Secret you received from Twitter\r\n    private string secret = \"\";\r\n\r\n    \/\/ 3 - The coroutine the will make the authorization request\r\n    private IEnumerator MakeOAuthRequest(string apiKey, string apiSecret)\r\n    {\r\n        string oAuthUrl = \"https:\/\/api.twitter.com\/oauth2\/token\";\r\n        \r\n        \/\/ 3-1\r\n        byte[] body = Encoding.UTF8.GetBytes(\"grant_type=client_credentials\");\r\n\r\n        \/\/ 3-2\r\n        Dictionary&lt;string, string&gt; headers = new Dictionary&lt;string, string&gt;();\r\n        string base64KeyAndSecret = \r\n            Convert.ToBase64String(Encoding.UTF8.GetBytes(apiKey + \":\" + apiSecret));\r\n\r\n        headers.Add(\"Authorization\", \"Basic \" + base64KeyAndSecret);\r\n\r\n        \/\/ 3-3\r\n        WWW request = new WWW(oAuthUrl, body, headers);\r\n        yield return request;\r\n\r\n        \/\/ 3-4\r\n        if (!string.IsNullOrEmpty(request.error))\r\n        {\r\n            Debug.LogErrorFormat(\"UnityEngine.WWW Error: {0}\", request.error);\r\n        }\r\n        \r\n        Debug.Log(\"Response: \" + request.text);\r\n    }\r\n\r\n    \/\/ 4 - Just run authorization on start for now.\r\n    private void Start() \r\n    {\r\n        StartCoroutine(MakeOAuthRequest(apiKey, secret));\r\n    }\r\n\r\n...<\/pre>\n<ol>\n<li><span class=\"lang:c# highlight:0 decode:true crayon-inline \">apiKey<\/span>\u00a0: Enter your Consumer API Key here.<\/li>\n<li><span class=\"lang:c# highlight:0 decode:true crayon-inline \">secret<\/span>\u00a0: Enter your Consumer Secret here.<\/li>\n<li><span class=\"lang:c# highlight:0 decode:true crayon-inline\">MakeOAuthRequest(string apiKey, string apiSecret)<\/span>\u00a0: This coroutine runs a Unity WWW request to Twitter&#8217;s OAuth URL.\n<ol>\n<li>The body of this request needs to be a byte array from the string <span class=\"lang:c# highlight:0 decode:true crayon-inline \">&#8220;grant_type=client_credentials&#8221;<\/span>\u00a0.<\/li>\n<li>The WWW request must have an Authorization header with the apiKey and apiSecret. These must be encoded to a byte array and then converted to a base64 string as is show in the code.<\/li>\n<li>The request is sent and the coroutine continues its execution when a response (or error) is received.<\/li>\n<li>\u00a0After the response is received check to see if it was an error and output that information to the console. Also output to the console any text data that was received.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>Create an empty game object in your scene and name it\u00a0<strong>TwitterSearchHandler<\/strong>. Add the script to it as a component and run the scene. If the request was successful the console should have a message like this:<\/p>\n<pre class=\"wrap:true lang:c# highlight:0 decode:true \">Response: {\"token_type\":\"bearer\",\"access_token\":\"AAAAAAAAAAAAAAAAAAAAACopygAAAAAAOzSaoftcn3tdOI0m4qDfGgyfpdc%3DhoTSgBMM1dHnWUuJB4zPpMNsnrsksAl6f6cgnHJrgceTrZ1qqD\"}<\/pre>\n<p>This is the access token that will be used by your app to make future requests. The actual token you see should be different. The important part is that you don&#8217;t get an error message. If you do, double check your API keys and the code to ensure everything is being sent correctly. This can be difficult, so don&#8217;t be discouraged if you get it wrong the first time (just do a Google search and see how many people failed their first time!).<\/p>\n<h3>Handling The Authorization Response<\/h3>\n<p>Most of the time you&#8217;ll want to do something with the response from an HTTP request. One of the best ways to do this is by creating a delegate type that can pass the response data to some other method. You&#8217;ll add a parameter to your coroutine so that you can assign the delegate and call (or Invoke) the delegate when a response is received. A delegate is a reference to a method that can be called at some later time. This is really handy for making your requesting method (in this case the MakeOAuthRequest coroutine) generic and able to do a variety of different things when the response is received.<\/p>\n<p>Create a new file and name it <strong>OAuthResponse.cs\u00a0<\/strong>this will contain the delegate definition for the response and the object that will hold the response data. First, create a public class called <strong>OAuthResponse<\/strong> like so:<\/p>\n<pre class=\"lang:c# decode:true\" title=\"OAuthResponse.cs\">public class OAuthResponse\r\n{\r\n\t\/\/ 1\r\n\tpublic string token_type;\r\n\tpublic string access_token;\r\n\t\/\/ 2\r\n\tpublic bool isValid\r\n\t{\r\n\t\tget\r\n\t\t{\r\n\t\t\treturn !string.IsNullOrEmpty(token_type) &amp;&amp; !string.IsNullOrEmpty(access_token);\r\n\t\t}\r\n\t}\r\n\r\n\t\/\/ 3\r\n\tpublic override string ToString()\r\n\t{\r\n\t\treturn string.Format(\r\n\t\t\t\"isValid: {0}\\ntoken_type: {1}\\naccess_token: {2}\",\r\n\t\t\tisValid,\r\n\t\t\t(string.IsNullOrEmpty(token_type) ? \"NULL\" : token_type),\r\n\t\t\t(string.IsNullOrEmpty(access_token) ? \"NULL\" : access_token)\r\n\t\t\t);\r\n\t}\r\n}<\/pre>\n<ol>\n<li>Take a look at the string that was returned from the OAuth request in the previous section. Notice that is has 2 variables in it: <span class=\"lang:c# highlight:0 decode:true crayon-inline \">token_type<\/span>\u00a0 and <span class=\"lang:c# highlight:0 decode:true crayon-inline \">access_token<\/span>\u00a0. These are defined in the above class with the same exact names. The name must be the same as the response&#8217;s string for the Json serialization to know where to put the values (unless you tell Json.NET otherwise &#8211; more on that later). The variable types must also be appropriate (i.e. in this case they are both strings).<\/li>\n<li><span class=\"lang:c# highlight:0 decode:true crayon-inline \">isValid<\/span>\u00a0: This preforms a simple check to ensure that neither of the variables are empty (or null). If they are then something went wrong.<\/li>\n<li><span class=\"lang:c# highlight:0 decode:true crayon-inline \">ToString()<\/span>\u00a0: Whenever you create a model class (or pretty much any class) it&#8217;s a good practice to override ToString so that you can easily examine and debug the object.<\/li>\n<\/ol>\n<p>Now that you have the model object defined you can also define the delegate type that can receive this object. This can go in the same file or it&#8217;s own separate file if you like. Since the delegate is specific to the OAuthResponse object, it&#8217;s a good idea to place it in the same file so there&#8217;s little need to search for it (and it only requires a single line).<\/p>\n<pre class=\"lang:c# decode:true \">public delegate void OAuthResponseDelegate(OAuthResponse response);<\/pre>\n<p>Back in the <strong>TwitterSearchHandler<\/strong> class add <span class=\"lang:c# highlight:0 decode:true crayon-inline \">using Newtonsoft.Json<\/span>\u00a0 to the top of the file and redefine the MakeOAuthRequest() coroutine like so:<\/p>\n<pre class=\"lang:c# decode:true\">using Newtonsoft.Json;\r\n...\r\n...\r\n\tprivate IEnumerator MakeOAuthRequest(\r\n\t\tstring apiKey, \r\n\t\tstring apiSecret, \r\n\t\t\/\/ 1\r\n\t\tOAuthResponseDelegate OnResponse)\r\n\t{\r\n\t\tstring oAuthUrl = \"https:\/\/api.twitter.com\/oauth2\/token\";\r\n\r\n\t\tbyte[] body = Encoding.UTF8.GetBytes(\"grant_type=client_credentials\");\r\n\r\n\t\tDictionary&lt;string, string&gt; headers = new Dictionary&lt;string, string&gt;();\r\n\r\n\t\tstring base64KeyAndSecret = \r\n\t\t\tConvert.ToBase64String(Encoding.UTF8.GetBytes(apiKey + \":\" + apiSecret));\r\n\r\n\t\theaders.Add(\"Authorization\", \"Basic \" + base64KeyAndSecret);\r\n\r\n\t\tWWW request = new WWW(oAuthUrl, body, headers);\r\n\r\n\t\tyield return request;\r\n\r\n\t\t\/\/ 2\r\n\t\tif (!string.IsNullOrEmpty(request.error))\r\n\t\t{\r\n\t\t\tDebug.LogErrorFormat(\"UnityEngine.WWW Error: {0}\", request.error);\r\n\t\t}\r\n\r\n\t\t\/\/ 3\r\n\t\tOAuthResponse response = null;\r\n\r\n\t\t\/\/ 4\r\n\t\tif (!string.IsNullOrEmpty(request.text))\r\n\t\t{\r\n\t\t\tresponse = JsonConvert.DeserializeObject&lt;OAuthResponse&gt;(request.text);\r\n\t\t\tDebug.LogFormat(\"OAuthResponse:\\n{0}\", response.ToString());\r\n\t\t}\r\n\r\n\t\t\/\/ 5\r\n\t\tif (OnResponse != null)\r\n\t\t\tOnResponse.Invoke(response);\r\n\t}\r\n...<\/pre>\n<ol>\n<li>This new parameter will allow you to assign the delegate&#8217;s method that will be called when the request finishes.<\/li>\n<li>Now the class really only needs to report the error string if it is not empty.<\/li>\n<li>Create a variable (<span class=\"lang:c# highlight:0 decode:true crayon-inline \">response<\/span>\u00a0) to contain the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OAuthResponse<\/span>\u00a0 object, set it to null for now.<\/li>\n<li>Only attempt to convert the request.text to an OAuthResponse if request.text is not empty. Deserialization of the Json string (request.text) is a simple single line. While in development it&#8217;s a good idea to output the string representation of the OAuthResponse so that you can check it in the console.<\/li>\n<li>If the delegate method is not null (this would only happen if someone decided to actually input <span class=\"lang:c# highlight:0 decode:true crayon-inline\">null<\/span>\u00a0as the parameter&#8230;), then Invoke the delegate and pass through the OAuthResponse object (<span class=\"lang:c# highlight:0 decode:true crayon-inline \">response<\/span>\u00a0) as its parameter.<\/li>\n<\/ol>\n<p>Now that the MakeOAuthRequest method has been rewritten to allow a delegate parameter you&#8217;ll also want to define a method that will handle the response. In this application you&#8217;ll want to make a search request when the OAuth is valid. Add the following method to the TwitterSearchHandler class:<\/p>\n<pre class=\"lang:c# decode:true\">...\r\n\tprivate void MakeSearchRequest(OAuthResponse response)\r\n\t{\r\n\t\tif (response == null || !response.isValid)\r\n\t\t{\r\n\t\t\tDebug.LogError(\"response is null or invalid\");\r\n\t\t\treturn;\r\n\t\t}\r\n\t\t\r\n\t\tDebug.Log(\"Authorization received\");\r\n\t}\r\n...<\/pre>\n<p>As you can see, this method doesn&#8217;t do anything special yet, but you need it so that you can rewrite the class&#8217;s StartCoroutine call to MakeOAuthRequest.\u00a0You&#8217;re also not going to always want to run the authorization from the Start method, so create another method that will eventually be used via a UI element to run the entire authorization and search procedure:<\/p>\n<pre class=\"lang:c# decode:true\">...\r\n\tprivate string query = \"\";\r\n\tpublic void MakeSearchRequest(string query)\r\n\t{\r\n\t\tthis.query = query;\r\n\r\n\t\tif (!string.IsNullOrEmpty(apiKey))\r\n\t\t{\r\n\t\t\tStartCoroutine(MakeOAuthRequest(apiKey, secret, MakeSearchRequest));\r\n\t\t}\r\n\t}\r\n...<\/pre>\n<p>Now your Start method can be rewritten as this for now:<\/p>\n<pre class=\"lang:c# decode:true \">...\r\n\tprivate void Start() \r\n\t{\r\n\t\tMakeSearchRequest(\"\");\r\n\t}\r\n...<\/pre>\n<p>Now run the scene and you should have the following output in your console (the actual access_token will vary):<\/p>\n<pre class=\"lang:c# highlight:0 decode:true\">OAuthResponse:\r\nisValid: True\r\ntoken_type: bearer\r\naccess_token: AAAAAAAAAAAAAAAAAAAA<\/pre>\n<p>So far this doesn&#8217;t really do anything different than before, but that will come soon. Before you go much further you&#8217;ll need a way to read the errors that might be sent back from the Twitter API.<\/p>\n<h3>Handling Twitter API Errors<\/h3>\n<p>Valid responses are great, but what happens when the API responds with an error? To check this out you can add a line to output the request.text to the console via the MakeOAuthRequest coroutine. Simply change your API key and the API will return a Json object like this:<\/p>\n<p><span class=\"lang:c# highlight:0 decode:true crayon-inline \">{&#8220;errors&#8221;:[{&#8220;code&#8221;:99,&#8221;message&#8221;:&#8221;Unable to verify your credentials&#8221;,&#8221;label&#8221;:&#8221;authenticity_token_error&#8221;}]}<\/span><\/p>\n<p>The structure of this Json object is like so:<\/p>\n<ul>\n<li><strong>errors<\/strong>: this is an array (notice the [ and ]). There could be more than one error.\n<ul>\n<li><strong>code<\/strong>: an integer representing some error code.<\/li>\n<li><strong>message<\/strong>: a string providing more information on the error.<\/li>\n<li><strong>label<\/strong>: a string that is a more technical description of the error.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Create another class and call it <strong>Error<\/strong>. It&#8217;s\u00a0pretty short and just contains public properties to contain the array elements that were outlined above.<\/p>\n<pre class=\"lang:c# decode:true \" title=\"Error.cs\">public class Error\r\n{\r\n\tpublic int code;\r\n\tpublic string message;\r\n\tpublic string label;\r\n\r\n\tpublic override string ToString()\r\n\t{\r\n\t\treturn string.Format(\r\n\t\t\t\"code: {0}\\nmessage: {1}\\nlabel: {2}\",\r\n\t\t\tcode, message, label);\r\n\t}\r\n}<\/pre>\n<p>Since the response can contain an array of errors it will also be helpful to easily convert those to a single string. Define the following extension class to help out with that.<\/p>\n<pre class=\"lang:c# decode:true \" title=\"ErrorExt\">public static class ErrorExt\r\n{\r\n\tpublic static string ToStringExt(this Error[] errors, string separator = \"\\n\")\r\n\t{\r\n\t\tstring s = \"\";\r\n\r\n\t\tfor (int i = 0; i &lt; errors.Length; i++)\r\n\t\t{\r\n\t\t\ts += errors[i].ToString();\r\n\t\t\tif (i &lt; errors.Length - 1)\r\n\t\t\t\ts += separator;\r\n\t\t}\r\n\r\n\t\tif (string.IsNullOrEmpty(s))\r\n\t\t\ts = \"NONE\";\r\n\r\n\t\treturn s;\r\n\t}\r\n}<\/pre>\n<p>Now that the Error class is all set up you can make use of it in the OAuthResponse class. It is also possible that other requests will have errors, so the Error class will be reused when building other class models that contain the deserialized Json data. In the OAuthResponse class add the following public property to contain the array of possible errors:<\/p>\n<pre class=\"lang:c# decode:true\">...\r\n\tpublic Error[] errors;\r\n...<\/pre>\n<p>Also, rewrite the ToString() method to convert that array of errors to a string for output to the console. This will make use of that extension method you just wrote:<\/p>\n<pre class=\"lang:c# decode:true \">\tpublic override string ToString()\r\n\t{\r\n\t\treturn string.Format(                                     \/\/ NEW \r\n\t\t\t\"isValid: {0}\\ntoken_type: {1}\\naccess_token: {2}\\nerror(s):{3}\",\r\n\t\t\tisValid,\r\n\t\t\t(string.IsNullOrEmpty(token_type) ? \"NULL\" : token_type),\r\n\t\t\t(string.IsNullOrEmpty(access_token) ? \"NULL\" : access_token),\r\n\t\t\t\/\/ NEW\r\n\t\t\t((errors == null || errors.Length == 0) ? \"NONE\" : \"\\n\" + errors.ToStringExt())\r\n\t\t\t);\r\n\t}<\/pre>\n<p>Now, run the scene again with an incorrect API key and you should see the following in the console:<\/p>\n<pre class=\"lang:c# highlight:0 decode:true \">OAuthResponse:\r\nisValid: False\r\ntoken_type: NULL\r\naccess_token: NULL\r\nerror(s):\r\ncode: 99\r\nmessage: Unable to verify your credentials\r\nlabel: authenticity_token_error<\/pre>\n<p>Now the OAuthResponse class can contain error information if something goes wrong and you can easily read the information. Furthermore, now that the information is in a data structure you could actually do something with it. In this case it would be up to you, the developer to fix any errors with OAuth before releasing the product, but in other cases, like a user logging in to a system, you may want to provide some feedback to the user to tell them what went wrong.<\/p>\n<p>Have no fear! The application will be making search requests soon. You&#8217;ll need a couple more classes for that. You should start to see a pattern emerging in the code showing how much of this will be reusable.<\/p>\n<h3>Handling Search Responses<\/h3>\n<p>Twitter&#8217;s API has a search response structure that will require us to write two classes:<\/p>\n<ul>\n<li><strong>SimpleTweet<\/strong> &#8211; this class will contain the actual information for a specific twitter status (or tweet). My implementation isn&#8217;t using all of the data available, but just what we need. Take a look at the Twitter API reference for a full list of data available (<a href=\"https:\/\/dev.twitter.com\/overview\/api\/tweets\">https:\/\/dev.twitter.com\/overview\/api\/tweets<\/a>).<\/li>\n<li><strong>SearchResponse<\/strong> &#8211; this class contains an array of SimpleTweets to hold all of the statuses from the search, it also contains an array of errors. This is the structure of the Json response we will be getting back from the Twitter API.<\/li>\n<\/ul>\n<p>First, create a new class called <span class=\"lang:c# highlight:0 decode:true crayon-inline\">SimpleTweet<\/span>\u00a0and define it like so:<\/p>\n<pre class=\"lang:c# decode:true \" title=\"SimpleTweet.cs\">using Newtonsoft.Json;\r\n\r\npublic class SimpleTweet\r\n{\r\n    [JsonProperty(\"created_at\")]\r\n    public string createdAt { get; private set; }\r\n    [JsonProperty(\"id_str\")]\r\n    public string id { get; private set; }\r\n    [JsonProperty]\r\n    public string text { get; private set; }\r\n\r\n    public bool isValid\r\n    {\r\n        get\r\n        {\r\n            return !string.IsNullOrEmpty(text);\r\n        }\r\n    }\r\n\r\n    public override string ToString()\r\n    {\r\n        return string.Format(\r\n            \"created_at: {0}\\nid_str: {1}\\ntext: {2}\",\r\n            createdAt, id_str, text);\r\n    }\r\n}<\/pre>\n<p>Notice that I&#8217;m using something new here: the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">JsonProperty<\/span>\u00a0 attribute. I&#8217;m using it because I want the SimpleTweet model to have restricted access to the class&#8217;s properties. I want the properties to be read only. Therefore they have a public get and a private set. In the Error class I simply made these public. You <em>can<\/em> do that, but then you can&#8217;t be certain that some programmer in the future won&#8217;t decide to set one of those properties and muck something up. So in the name of good object oriented design, I&#8217;d prefer them to be only settable privately. Json.NET will automatically serialize public properties, but when access is restricted the property needs to use the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">JsonProperty<\/span>\u00a0 attribute so that the serializer knows it should set those variables. Also, the Json data property names (<span class=\"lang:c# highlight:0 decode:true crayon-inline\">created_at<\/span>\u00a0and <span class=\"lang:c# highlight:0 decode:true crayon-inline\">id_str<\/span>\u00a0) do not conform to typical C# naming conventions, so I use the\u00a0 <span class=\"lang:c# highlight:0 decode:true crayon-inline\">JsonProperty<\/span>\u00a0 attribute with its optional parameter of the incoming property name (i.e. the name that is used in the Json data string) to map it to a more properly named variable. Beyond that, there&#8217;s really no new concepts in this class. I have a public bool property to tell is if the SimpleTweet is valid (i.e. it isn&#8217;t an empty text response) and a simple ToString method to help us with any needed debugging.<\/p>\n<p>Next, we need a container for these SimpleTweets that conforms to the Json data response that will come from Twitter&#8217;s API. This is the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">SearchResponse<\/span>\u00a0 class.<\/p>\n<pre class=\"lang:c# decode:true \">using Newtonsoft.Json;\r\n\r\npublic delegate void SearchResponseDelegate(SearchResponse response);\r\n\r\npublic class SearchResponse\r\n{\r\n    [JsonProperty(\"statuses\")]\r\n    private SimpleTweet[] statusesIn;\r\n    [JsonIgnore]\r\n    public SimpleTweet[] statuses\r\n    {\r\n        get\r\n        {\r\n            if (statusesIn == null || statusesIn.Length &lt; 1)\r\n            {\r\n                return new SimpleTweet[0];\r\n            }\r\n\t\r\n            SimpleTweet[] immutable = new SimpleTweet[statusesIn.Length];\r\n            statusesIn.CopyTo(immutable, 0);\r\n            return immutable;\r\n        }\r\n    }\r\n\r\n    [JsonProperty(\"errors\")]\r\n    private Error[] errorsIn;\r\n    [JsonIgnore]\r\n    public Error[] errors\r\n    {\r\n        get\r\n        {\r\n            if (errorsIn == null || errorsIn.Length &lt; 1)\r\n                return new Error[0];\r\n\r\n            Error[] immutable = new Error[errorsIn.Length];\r\n            errorsIn.CopyTo(immutable, 0);\r\n            return errorsIn;\r\n        }\r\n    }\r\n\r\n    public override string ToString()\r\n    {\r\n        string statusesOut = \"\";\r\n\r\n        if (statuses == null)\r\n            statusesOut = \"\\tNULL\";\r\n        else if (statuses.Length &lt;= 0)\r\n            statusesOut = \"\\tno results\";\r\n        else\r\n        {\r\n            for (int i = 0; i &lt; statuses.Length; i++)\r\n            {\r\n                statusesOut += \"\\t\" + statuses[i].ToString();\r\n\r\n                if (i &lt; statuses.Length - 1)\r\n                    statusesOut += \"\\n\";\r\n            }\r\n        }\r\n\r\n        return string.Format(\"statuses:\\n{0}\\nerrors:{1}\", statusesOut, errors.ToStringExt());\r\n    }\r\n}<\/pre>\n<p>First, take note that I&#8217;ve defined a delegate, <span class=\"lang:c# highlight:0 decode:true crayon-inline \">SearchResponseDelegate<\/span>\u00a0, in this file. This will be used to handle callbacks when search requests are complete.<\/p>\n<p>Next, notice that I&#8217;m using the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">JsonProperty<\/span>\u00a0attribute again. This time I&#8217;m using it on private\u00a0fields because I want to do some operations on the public properties that will be accessed by other classes. Since those public properties may be serialized by Json.NET I&#8217;ve marked them with the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">JsonIgnore<\/span>\u00a0attribute. This isn&#8217;t entirely necessary because I&#8217;m only deserializing a Json data string into this class, but I wanted to show it to you, and who knows, we may have a reason to serialize this class back into a Json data string and if these properties were not ignored, then we&#8217;d have double the data in our string!<\/p>\n<p>One final note I&#8217;d like to mention is that I&#8217;m making these get accessors so that other classes can&#8217;t inadvertently make changes to the actual data. I&#8217;ve made it immutable by creating a copy of the input\/deserialized array. So any changes to the array that has been accessed (errors or statuses) doesn&#8217;t affect the underlying data. It is immutable.<\/p>\n<p>Now that we have our data classes (models) we can finally have a place where we can store the search responses and start displaying them (view).<\/p>\n<h3>Finalizing TwitterSearchHandler<\/h3>\n<p>We have a little bit of work left to do in the TwitterSearchHandler class so that we can finally deal with search result responses. At the top of the class you&#8217;ll need to add the following:<\/p>\n<pre class=\"lang:c# decode:true \">...\r\n\t\/\/ 1\r\n\tprivate OAuthResponse authorization;\r\n\r\n\t\/\/ 2\r\n\t[Serializable]\r\n\tpublic class HandleStatusesUnityEvent : UnityEngine.Events.UnityEvent&lt;SimpleTweet[]&gt; { }\r\n\tpublic HandleStatusesUnityEvent OnStatusesRecieved;\r\n...<\/pre>\n<ol>\n<li>Add an <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OAuthResponse<\/span>\u00a0object. We&#8217;ll use this to prevent repeated authorization requests because it&#8217;s not really necessary to get authorization before each request. We really only need to do it once in the life cycle of the app. We can also use the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OAuthResponse<\/span>\u00a0&#8216;s <span class=\"lang:c# highlight:0 decode:true crayon-inline \">isValid<\/span>\u00a0property to invalidate the authorization and tell us when to request a new one. I&#8217;m not going to cover that in this tutorial, but you&#8217;ll see it implemented in the final project.<\/li>\n<li>Create a class inside of <span class=\"lang:c# highlight:0 decode:true crayon-inline \">TwitterSearchHandler<\/span>\u00a0 called <span class=\"lang:c# highlight:0 decode:true crayon-inline \">HandleStatusesUnityEvent<\/span>\u00a0. This will need to be marked as <span class=\"lang:c# highlight:0 decode:true crayon-inline \">Serializable<\/span>\u00a0 so that the Unity Editor will display objects of this type it in the inspector, our object that will be accessible from the inspector is <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OnStatusesRecieved<\/span>\u00a0. This will add an area to the inspector where we can assign another class&#8217;s method just like what can be done in the OnClick callback for a Unity UI button. We&#8217;ll come back to this in the next section.<\/li>\n<\/ol>\n<p>Next,\u00a0we&#8217;ll need a coroutine to handle a WWW request for requesting the search via the Twitter API. Add the following method to <span class=\"lang:c# highlight:0 decode:true crayon-inline \">TwitterSearchHandler<\/span>\u00a0:<\/p>\n<pre class=\"lang:c# decode:true\" title=\"TwitterSearchHandler.MakeSearchRequest\">...\r\n\tpublic enum ResultType { mixed, recent, popular };\r\n\r\n\tIEnumerator MakeSearchRequestCoroutine(\r\n\t\tstring accessToken, string query, SearchResponseDelegate OnResponse,\r\n\t\tResultType resultType = ResultType.mixed, int count = 100)\r\n\t{\r\n\t\t\/\/ 1 \r\n\t\tstring url = \"https:\/\/api.twitter.com\/1.1\/search\/tweets.json?q=\" + WWW.EscapeURL(query);\r\n\r\n\t\tif (resultType != ResultType.mixed)\r\n\t\t\turl += \"&amp;result_type=\" + resultType.ToString();\r\n\r\n\t\tif (count &lt; 100)\r\n\t\t\turl += \"&amp;count=\" + count;\r\n\r\n\t\t\/\/ 2\r\n\t\tDictionary&lt;string, string&gt; headers = new Dictionary&lt;string, string&gt;();\r\n\t\theaders.Add(\"Authorization\", \"Bearer \" + accessToken);\r\n\r\n\t\t\/\/ 3\r\n\t\tWWW request = new WWW(url, null, headers);\r\n\r\n\t\tyield return request;\r\n\r\n\t\t\/\/ 4\r\n\t\tif (!string.IsNullOrEmpty(request.error))\r\n\t\t{\r\n\t\t\tDebug.LogErrorFormat(\"UnityEnigine.WWW Error: {0}\", request.error);\r\n\t\t}\r\n\r\n\t\t\/\/ 5\r\n\t\tSearchResponse searchResponse = null;\r\n\r\n\t\tif(!string.IsNullOrEmpty(request.text))\r\n\t\t{\r\n\t\t\tsearchResponse = JsonConvert.DeserializeObject&lt;SearchResponse&gt;(request.text);\r\n\t\t\tDebug.Log(searchResponse.ToString());\r\n\t\t}\r\n\r\n\t\t\/\/ 6\r\n\t\tif (OnResponse != null)\r\n\t\t\tOnResponse.Invoke(searchResponse);\r\n\t}\r\n...<\/pre>\n<p>Note the parameters for the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">MakeSearchRequestCoroutine()<\/span>\u00a0\u00a0coroutine. The required parameters are <span class=\"lang:c# highlight:0 decode:true crayon-inline \">accessToken<\/span>\u00a0 (obtained from our OAuth request), the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">query<\/span>\u00a0 to search for, and a <span class=\"lang:c# highlight:0 decode:true crayon-inline \">SearchResponseDelegate<\/span>\u00a0that will get called when the request completes. I&#8217;ve included 2 optional parameters <span class=\"lang:c# highlight:0 decode:true crayon-inline\">resultType<\/span>\u00a0and <span class=\"lang:c# highlight:0 decode:true crayon-inline\">count<\/span>. The <span class=\"lang:c# highlight:0 decode:true crayon-inline \">resultType<\/span>\u00a0can be one of three choices and defined by its enum: mixed, recent, or popular. I chose mixed as the default. The count puts a cap on the number of results retrieved.\u00a0Twitter&#8217;s API limits this to 100 by default, so if you enter a value for the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">count<\/span>\u00a0parameter that is less than 100 it will be used in the request.<\/p>\n<ol>\n<li>First we build the request URL string based off of the query, result type, and count.<\/li>\n<li>Next we define the the header which contains an Authorization key with the value Bearer and the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">accessToken<\/span>\u00a0. Pay special attention to the space after Bearer, it&#8217;s important.<\/li>\n<li>Now we send up the request and continue execution when we have our response.<\/li>\n<li>If the request has an error then write a console message for the developer to see.<\/li>\n<li>If the request.text (the response) is not empty the deserialize it into our new <span class=\"lang:c# highlight:0 decode:true crayon-inline \">SearchResponse<\/span>\u00a0object. We&#8217;ll also output this to the console so that we can see the results without having the app&#8217;s UI all connected. This should be removed before production.<\/li>\n<li>Finally invoke the delegate with the values from the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">searchResponse<\/span>.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Next, you&#8217;ll need a method that can be used to handle that response. This will be used as the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">MakeSearchRequestCoroutine()<\/span>&#8216;s <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OnResponse<\/span>\u00a0 parameter. Note that this method must have a parameter with the type <span class=\"lang:c# highlight:0 decode:true crayon-inline \">SearchResponse<\/span>\u00a0 to be used as this delegate type.<\/p>\n<pre class=\"lang:c# decode:true\" title=\"TwitterSeachHandler.HandleSearchResponse\">...\r\n\tprivate void HandleSearchResponse(SearchResponse response)\r\n\t{\r\n\t\t\/\/ 1\r\n\t\tif (response == null || response.statuses == null)\r\n\t\t{\r\n\t\t\tDebug.LogError(\"Invalid response: NULL\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t\/\/ 2\r\n\t\tif (response.statuses.Length == 0)\r\n\t\t{\r\n\t\t\tDebug.LogError(\"No results\");\r\n\t\t\t\/\/ A good point to ask the user if they'd like to try another query\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t\/\/ 3\r\n\t\tif (OnStatusesRecieved != null)\r\n\t\t\tOnStatusesRecieved.Invoke(response.statuses);\r\n\t}\r\n...<\/pre>\n<ol>\n<li>If the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">response<\/span>\u00a0is null or the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">response.statuses<\/span>\u00a0is null (the array of actual tweets) then we log the error for the developer to handle.<\/li>\n<li>If the\u00a0 <span class=\"lang:c# highlight:0 decode:true crayon-inline\">response.statuses<\/span>\u00a0 array contains 0 elements then we didn&#8217;t get any results. This would be a good point to show an alert to the user asking them to try another search.<\/li>\n<li>Finally, we invoke <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OnStatusesRecieved<\/span>\u00a0which we declared in the first part of this section. This will be assigned in the inspector and will call another method in another class that will handle the display (view) of the results. We&#8217;ll be doing that in the next section.<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Next, you&#8217;ll need to redefine the MakeSearchRequest(OAuthResponse response) method to start our MakeSearchRequest coroutine like so:<\/p>\n<pre class=\"lang:c# decode:true\" title=\"TwitterSearchHandler.MakeSearchRequest\">\tprivate void MakeSearchRequest(OAuthResponse response)\r\n\t{\r\n\t\tif (response == null || !response.isValid)\r\n\t\t{\r\n\t\t\tDebug.LogError(\"response is null or invalid\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t\/\/ 1\r\n\t\tauthorization = response;\r\n\r\n\t\t\/\/ 2\r\n\t\tStartCoroutine(\r\n\t\t\tMakeSearchRequestCoroutine(\r\n\t\t\t\tresponse.access_token, \r\n\t\t\t\tquery, \r\n\t\t\t\tHandleSearchResponse,\r\n\t\t\t\tcount: 10));\r\n\t}<\/pre>\n<ol>\n<li>First we&#8217;ll now store the response in the class&#8217;s authorization field so that we don&#8217;t unnecessarily reauthorize the user (we&#8217;ll be modifying <span class=\"lang:c# highlight:0 decode:true crayon-inline\">MakeOAuthRequest<\/span>\u00a0to hand this for us next).<\/li>\n<li>Next we simply start the new <span class=\"lang:c# highlight:0 decode:true crayon-inline \">MakeSearchRequestCoroutine<\/span>\u00a0with the proper parameters: the response&#8217;s <span class=\"lang:c# highlight:0 decode:true crayon-inline \">access_token<\/span>\u00a0, the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">query<\/span>\u00a0we want to search for, our new <span class=\"lang:c# highlight:0 decode:true crayon-inline \">HandleSearchResponse<\/span>\u00a0method as the callback for when the request receives a response, and I&#8217;ve defined the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">count<\/span>\u00a0to be 10 just to give us a quick, small response (feel free to change that to whatever you like &#8211; less than 100 &#8212; or omit it for up to 100 results).<\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p>Now you should change the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">MakeOAuthRequest<\/span>\u00a0coroutine to skip future authorization requests instead of getting authorization every time a search request is made. Add the following to the beginning of the <span class=\"lang:c# highlight:0 decode:true crayon-inline\">MakeOAuthRequest<\/span>\u00a0method:<\/p>\n<pre class=\"lang:c# decode:true\" title=\"TwitterSearchHandler.MakeOAuthRequest change\">...\r\n\t\t\/\/ Skip future authorization requests.\r\n\t\tif (authorization != null &amp;&amp; authorization.isValid &amp;&amp; OnResponse != null)\r\n\t\t{\r\n\t\t\tOnResponse.Invoke(authorization);\r\n\t\t\tDebug.Log(\"Do not reauth\");\r\n\t\t\tyield break;\r\n\t\t}\r\n\t\t\r\n...<\/pre>\n<p>&nbsp;<\/p>\n<p>Finally, change <span class=\"lang:c# highlight:0 decode:true crayon-inline \">MakeSearchRequest(&#8220;&#8221;);<\/span>\u00a0<span class=\"crayon-sy\">\u00a0in the start method to perform an actual search. Try <span class=\"lang:c# highlight:0 decode:true crayon-inline\">&#8220;NaplandGames&#8221;<\/span>\u00a0 as the parameter (note the lack of a space). You should now run the project and make sure it is free of errors. The\u00a0search results will only appear in the console for now. In the next section we&#8217;ll create a script that will handle the display of the results in UI. Here&#8217;s what the console log should look like:<br \/>\n<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-search-result-console.png\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-medium wp-image-274\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-search-result-console-300x113.png\" alt=\"\" width=\"300\" height=\"113\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-search-result-console-300x113.png 300w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-search-result-console-768x289.png 768w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-search-result-console.png 926w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/span><\/p>\n<p>&nbsp;<\/p>\n<h3>Displaying The Search Results<\/h3>\n<p>In the final part of this tutorial we&#8217;ll be creating a class that will handle the display of the search results in Unity&#8217;s UI. This is the view component of the application. After the class is created we&#8217;ll connect it to the TwitterSearchHandler class via Unity&#8217;s inspector. Create a new MonoBehviour derived class (or script) and call it TwitterStatusViewHandler below are the contents of that class:<\/p>\n<pre class=\"lang:c# decode:true\" title=\"TwitterStatusViewHandler.cs\">using UnityEngine;\r\nusing UnityEngine.UI;\r\nusing System.Collections;\r\nusing NG.TwitterApi;\r\n\r\npublic class TwitterStatusViewHandler : MonoBehaviour\r\n{\r\n\t\/\/ 1\r\n\t[SerializeField]\r\n\tprivate Text text;\r\n\r\n\t\/\/ 2\r\n\t[SerializeField]\r\n\tprivate float delay = 2;\r\n\r\n\t\/\/ 3\r\n\tprivate IEnumerator displayCoroutine;\r\n\r\n\t\/\/ 4\r\n\tvoid Awake()\r\n\t{\r\n\t\tif (text == null)\r\n\t\t\tDebug.LogError(\"Text is null!\");\r\n\t}\r\n\r\n\r\n\t\/\/ 5\r\n\tpublic void DisplayStatuses(SimpleTweet[] statuses)\r\n\t{\r\n\t\tif (statuses == null || statuses.Length &lt; 1)\r\n\t\t{\r\n\t\t\tDebug.LogError(\"No statuses to display\");\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (displayCoroutine != null)\r\n\t\t\tStopCoroutine(displayCoroutine);\r\n\r\n\t\tdisplayCoroutine = DisplayCoroutine(statuses, delay);\r\n\t\tStartCoroutine(displayCoroutine);\r\n\t}\r\n\r\n\t\/\/ 6\r\n\tIEnumerator DisplayCoroutine(SimpleTweet[] statuses, float delay)\r\n\t{\r\n\t\tWaitForSeconds wait = new WaitForSeconds(delay);\r\n\t\tint statusIndex = 0;\r\n\t\twhile(true)\r\n\t\t{\r\n\t\t\ttext.text = statuses[statusIndex].text;\r\n\t\t\tstatusIndex++;\r\n\t\t\tif (statusIndex &gt;= statuses.Length)\r\n\t\t\t\tstatusIndex = 0;\r\n\r\n\t\t\tyield return wait;\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<ol>\n<li>Define a UI Text field called <span class=\"lang:c# highlight:0 decode:true crayon-inline \">text<\/span>\u00a0 that will be assigned in the editor. This is where the Tweets will be displayed one at a time.<\/li>\n<li>Define a float called <span class=\"lang:c# highlight:0 decode:true crayon-inline\">delay<\/span>, this is the amount of time a single Tweet is displayed for.<\/li>\n<li>The <span class=\"lang:c# highlight:0 decode:true crayon-inline \">displayCoroutine<\/span>\u00a0field will hold a reference to the currently running coroutine so it can be stopped when we want to display a new set of search results.<\/li>\n<li>I the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">Awake<\/span>\u00a0method we simply make sure to warn the developer that a UI Text object should be assigned otherwise we&#8217;ll get errors!<\/li>\n<li>The <span class=\"lang:c# highlight:0 decode:true crayon-inline\">DisplayStatuses()<\/span>\u00a0method will take a parameter that is an array of statuses that is received from the request. This method will be assigned to the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">TwitterSearchHandler<\/span>\u00a0&#8216;s <span class=\"lang:c# highlight:0 decode:true crayon-inline \">OnStatusesRecieved<\/span>\u00a0event via the inspector. The <span class=\"lang:c# highlight:0 decode:true crayon-inline \">DisplayStatuses<\/span>\u00a0method simply stops the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">displayCoroutine<\/span>\u00a0if it is running, then starts a new <span class=\"lang:c# highlight:0 decode:true crayon-inline\">DisplayCoroutine<\/span>.<\/li>\n<li>Finally, the <span class=\"lang:c# highlight:0 decode:true crayon-inline \">DisplayCoroutine<\/span>\u00a0method is responsible for iterating through the array of statuses and displaying them after the specified delay. Note that it will start back at index 0 when the end of the array is reached. This will give us a continuous display until a new search response is received.<\/li>\n<\/ol>\n<p>Now all we need to do is hook it all up in our scene.<\/p>\n<h4>Setting Up The Scene<\/h4>\n<p>If you downloaded the starter project then most of this work will already be done. All you&#8217;ll need to do is connect the scripts. If you haven&#8217;t downloaded the starter project then here&#8217;s a quick breakdown of the scene:<\/p>\n<ol>\n<li>Set up the project to be 2D and the game view in some portrait mode like 9:16.<\/li>\n<li>Add a main camera with a Solid Color clear flag, the color should be a very light grey. The camera should also be Orthographic with a size of 5.<\/li>\n<li>Add a Canvas with the canvas scaler set to Scale With Screen Size and the Screen Match Mode to Shrink\n<ol>\n<li>Add a child Text object to the Canvas that stretches to the Canvas size, center the text horizontally and vertically.<\/li>\n<li>Add a child Image object to the Canvas that serves as a visual indicator for searching. I used a simple UI sprite as the background then added a child Image to that which is a magnifying glass icon. Neither of these actually do anything, but serve only as an aesthetic. This is placed in the lower right of the screen.<\/li>\n<li>Add a child InputField object to the Canvas. I&#8217;ve positioned mine at the bottom of the screen and sized it so that the search icon fits to its right. I also set the Placeholder&#8217;s text to be &#8220;Search&#8230;&#8221;.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>The scene should look something like this when you&#8217;re done:<\/p>\n<p><a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-scene-setup.png\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-275\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-scene-setup.png\" alt=\"\" width=\"456\" height=\"490\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-scene-setup.png 456w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/twitterapi-scene-setup-279x300.png 279w\" sizes=\"(max-width: 456px) 100vw, 456px\" \/><\/a><\/p>\n<p>Now that the scene is all set up you can start adding and connecting the scripts we&#8217;ve created.<\/p>\n<ol>\n<li>First, add an empty game object to the scene and name it TwitterSearch.\n<ol>\n<li>Add the TwitterSearchHandler script to it.<\/li>\n<li>Add the TwitterStatusViewHandler script to it.<\/li>\n<li>In the TwitterSearchHandler component&#8217;s On Statuses Received Event add the TwitterStatusViewHandler&#8217;s DisplayStatuses method (make sure to select from the Dynamic section of the drop down)<\/li>\n<li>Finally, attach the Text object to the text field of the TwitterStatusViewHandler.<br \/>\n<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/00_twitter_searcher-1.gif\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-277 size-full\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/00_twitter_searcher-1.gif\" width=\"687\" height=\"450\" \/><br \/>\n<\/a><\/li>\n<\/ol>\n<\/li>\n<li>Finally, select the input field and assign its On End Edit event to be the TwitterSearchHandler&#8217;s MakeSearchRequest method (again make sure to select from the Dynamic section of the list). This event will be fired when the user hits enter after typing in the input field or if the tap\/click anywhere outside of the input field (like on the search &#8220;button&#8221;).<br \/>\n<a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/01_twitter_searcher.gif\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-278\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2017\/01\/01_twitter_searcher.gif\" alt=\"\" width=\"687\" height=\"873\" \/><br \/>\n<\/a><\/li>\n<li>Finally, make sure that the Start method of the TwitterSearchHandler no longer calls MakeSearchRequest as this will all be done through the UI.<\/li>\n<\/ol>\n<p>Now run the scene and type some search string into the input field. When you tap\/click outside of that field the search request is made and the results are displayed in the app!<\/p>\n<p><a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/00_twitter_searcher.gif\" rel=\"lightbox[221]\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-223 aligncenter\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/12\/00_twitter_searcher.gif\" alt=\"Twitter Search 1.0\" width=\"253\" height=\"445\" \/><\/a><\/p>\n<p>You now have a fully functioning Twitter search app and the basis of using the twitter API.<\/p>\n<p>The final project can be found here:\u00a0<a href=\"https:\/\/github.com\/Naphier\/UnityJsonTwitterTutorial\/releases\">https:\/\/github.com\/Naphier\/UnityJsonTwitterTutorial\/releases<\/a>. Note that I have added some minor changes to time-out the authorization and contain my work in its own namespace.<\/p>\n<h3>Further Exploration<\/h3>\n<p>I&#8217;d suggest reading more on the Twitter API here:\u00a0<a href=\"https:\/\/dev.twitter.com\/overview\/api\">https:\/\/dev.twitter.com\/overview\/api<\/a>. \u00a0Take a look at the &#8220;entities&#8221; object that comes with the status and use the &#8220;media_url&#8221; to fetch and display an image associated with a Tweet. Or maybe take a look at the &#8220;user&#8221; object that comes with the status and fetch and display the user&#8217;s profile image (&#8220;profile_image_url&#8221;). There&#8217;s a lot to explore in these status objects! Maybe explorer Json.NET further and save some of the responses to a file to load later.<\/p>\n<h3>Final Thoughts<\/h3>\n<p>Although I&#8217;ve used Json.NET for deserializing the Json objects, Unity does have a JsonUtilitly class that may suit basic needs. There&#8217;s also a ton of other Json solutions for Unity. One of note is FastJson (<a href=\"https:\/\/github.com\/mgholam\/fastJSON\">https:\/\/github.com\/mgholam\/fastJSON<\/a>). This boasts much greater speeds that Json.NET, but it does have some drawbacks such as the inability to serialize private fields or make use of special constructors for classes. Hopefully the author (or community) will extend it to that functionality soon (and be able to keep their awesome speed).<\/p>\n<p>Make sure to read my other article on basic serialization and saving data in Unity. As always, thanks for reading and don&#8217;t forget to subscribe!<\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_221\" class=\"pvc_stats all  \" data-element-id=\"221\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Why Json.NET? Unity does now include a Json utility, but it falls flat in many cases. It doesn&#8217;t serialize nested classes well (classes with multiple levels of inheritance), it can&#8217;t rename the Json object&#8217;s variables to something more appropriate for your code base, and there&#8217;s really not a lot of options. However, it does claim to be &#8220;&#8230;significantly faster than popular .NET JSON solutions&#8230;&#8221;. One of my favorite features of Json.NET is that it can easily serialize private fields and public fields with private setters. This allows for maintaining access restriction in you code base&#8217;s models without requiring the use&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/naplandgames.com\/blog\/2017\/01\/29\/data-serialization-part-2-unity3d-json-net-and-twitter-rest-api\/\">Continue reading<span class=\"screen-reader-text\">Data Serialization Part 2 &#8211; Unity3D, Json.NET, and Twitter REST API<\/span><\/a><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_221\" class=\"pvc_stats all  \" data-element-id=\"221\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[46,51,52,48,49,50,47,54,39,45,53,13,7],"_links":{"self":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/221"}],"collection":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/comments?post=221"}],"version-history":[{"count":23,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/221\/revisions"}],"predecessor-version":[{"id":317,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/221\/revisions\/317"}],"wp:attachment":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/media?parent=221"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/categories?post=221"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/tags?post=221"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}