GoogleCloudPlatform / gradle-appengine-templates

Freemarker based templates that build with the gradle-appengine-plugin
438 stars 205 forks source link

Use Retrofit to Connect to Google App Engine Servlets #63

Closed troy21688 closed 8 years ago

troy21688 commented 8 years ago

Please see post also on StackOverflow: http://stackoverflow.com/questions/35045684/need-help-connecting-to-google-app-engine-with-retrofit

I have successfully followed the Google tutorial, using the Android Studio Servlets module to connect to Google App Engine. I was able to see the Toast message on my device, meaning I successfully connected to the server and received a response.

I noticed that this module uses AsyncTask to handle the background tasks. From what I understand, Retrofit is a much simpler and effective method of handling tasks in the background thread. I am basically trying to replicate the Google Tutorial mentioned above using Retrofit 1.9.0 instead of the ServletPostAsyncTask Java class that they provide.

Below is my code:

MainActivity:

    public class MainActivity extends AppCompatActivity {

    //set the URL of the server, as defined in the Google Servlets Module Documentation
    private static String PROJECT_URL = "http://retrofit-test-1203.appspot.com/hello";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        //Instantiate a new RestAdapter Object, setting the endpoint as the URL of the server
        RestAdapter restAdapter = new RestAdapter.Builder()
                .setEndpoint(PROJECT_URL)
                .build();

        //Instantiate a new UserService object, and call the "testRequst" method, created in the interface
        //to interact with the server
        UserService userService = restAdapter.create(UserService.class);
        userService.testRequest("Test_Name", new Callback<String>() {
            @Override
            public void success(String s, Response response) {
                Toast.makeText(getApplicationContext(), response.toString(), Toast.LENGTH_LONG).show();

            }

            @Override
            public void failure(RetrofitError error) {
                Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_LONG).show();
            }
        });

      }
    }

UserService Interface, required by Retrofit:


    public interface UserService {

    static String PROJECT_URL = "http://retrofit-test-1203.appspot.com/hello";

    @POST(PROJECT_URL)
    void testRequest(@Query("test") String test, Callback<String> cb);

    }

My Servlet, as required by the Google Servlets Module:


> ```
> public class MyServlet extends HttpServlet {
> @Override
> public void doGet(HttpServletRequest req, HttpServletResponse resp)
>         throws IOException {
>     resp.setContentType("text/plain");
>     resp.getWriter().println("Please use the form to POST to this url");
> }
> 
> @Override
> public void doPost(HttpServletRequest req, HttpServletResponse resp)
>         throws IOException {
>     String name = req.getParameter("name");
>     resp.setContentType("text/plain");
>     if(name == null) {
>         resp.getWriter().println("Please enter a name");
>     }
>     resp.getWriter().println("Hello " + name);
>   }
> }
> ```

In my userService.testRequest()method, I pass in "Test_Name" as the string parameter. This text is what I hope to pass to the server, and then see a toast that displays "Hello Test_Name" (after receiving a server response), just like the Google App Engine Servlets module explains.

Any advice on using Retrofit with Google App Engine is appreciated, as there is limited documentation.
elharo commented 8 years ago

Perhaps. I haven't seen Retrofit before so I can't really say. However for purposes of tutorials, I think it's important to keep third party library dependencies to a minimum. This might make an interesting article on medium or some technical site if you care to write it up.

troy21688 commented 8 years ago

Do you know if it is at all possible to replicate with Retrofit?

On Thu, Jan 28, 2016 at 4:53 AM, Elliotte Rusty Harold < notifications@github.com> wrote:

Closed #63 https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63 .

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#event-529490421 .

Troy Chuinard, CPA

troy21688 commented 8 years ago

Also, when I want to change the server tasks, do I update the doInBackground() methods or the doPost() methods? Do you have additional tutorials on this concept?

akerekes commented 8 years ago

Disclaimer: I also don't have any experience with Retrofit, just took a quick glance at their site. The doInBackground() method runs on your client. If you want to change how you handle server response, you should change it there. The doPost() method of the servlet runs on the server-side so if you want to change the logic how the request is handled by the server (e.g. change the greeting from "Hello " to "Hi ", you should do it there.

troy21688 commented 8 years ago

The AsyncTask seems confusing. Assume I don't use Retrofit and I use the AsyncTask as normal, I have a few questions:

On the client side, I can have multiple activities / fragments, and each activity/fragment has unique methods. However, if I want the server to perform unique methods (i.e. change a String, change a boolean, add a number to a counter), how do I distinguish these different methods? Do I need to call .execute() multiple times? What do I change in the doInBackground() and doPost() methods? It seems there is limited documentation other than this basic Hello World example.

On Thu, Jan 28, 2016 at 10:24 AM, akerekes notifications@github.com wrote:

Disclaimer: I also don't have any experience with Retrofit, just took a quick glance at their site. The doInBackground() method runs on your client. If you want to change how you handle server response, you should change it there. The doPost() method of the servlet runs on the server-side so if you want to change the logic how the request is handled by the server (e.g. change the greeting from "Hello " to "Hi ", you should do it there.

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176261540 .

Troy Chuinard, CPA

akerekes commented 8 years ago

To handle different request from various clients is out of scope of this tutorial. To do it there are several options:

troy21688 commented 8 years ago

Do you have references to other tutorials that can handle different requests from multiple clients? Why is option 3 not recommended (it seems easiest)?

On Thu, Jan 28, 2016 at 10:37 AM, akerekes notifications@github.com wrote:

To handle different request from various clients is out of scope of this tutorial. To do it there are several options:

  • you can create multiple servlets and they will be mapped to different urls (as MyServlet is mapped to the /hello postfix)
  • you can use one of the many server side frameworks to handle the mapping of urls to server-side logic, e.g. Spring MVC
  • not recommended but still available option is to include a parameter into the request sent to the server (e.g. request type) and based on the value you can decide in doPost() what to do.

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176273515 .

Troy Chuinard, CPA

akerekes commented 8 years ago

Another disclaimer: I'm suggesting Spring only because that's what I have experience with. This tutorial gives a good intro to Spring: https://spring.io/guides/gs/rest-service/ By replicating the part where you add the greeting method annotated with @RequestMapping, you can add multiple endpoints for your clients. Third option seems the easiest, but on a longer term it's harder to maintain in my opinion.

troy21688 commented 8 years ago

So just to confirm, the AsyncTask Servlet Github example will not service multiple clients. For instance, if I have 1,000 users using my application (1,000 different clients), I cannot call the same .execute() method for each client?

On Thu, Jan 28, 2016 at 10:58 AM, akerekes notifications@github.com wrote:

Another disclaimer: I'm suggesting Spring only because that's what I have experience with. This tutorial gives a good intro to Spring: https://spring.io/guides/gs/rest-service/

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176282132 .

Troy Chuinard, CPA

troy21688 commented 8 years ago

Also, I am trying to find out how I would add multiple servlets to the same project so that I could have the server perform different functions, as previously mentioned. I take it that each servlet has to perform a different function (i.e. change a text value, set a boolean). From my understanding, one servlet cannot handle multiple tasks.

If so, please confirm this information. I appreciate your assistance!

On Thu, Jan 28, 2016 at 6:26 PM, Troy Chuinard tccpg288@gmail.com wrote:

So just to confirm, the AsyncTask Servlet Github example will not service multiple clients. For instance, if I have 1,000 users using my application (1,000 different clients), I cannot call the same .execute() method for each client?

On Thu, Jan 28, 2016 at 10:58 AM, akerekes notifications@github.com wrote:

Another disclaimer: I'm suggesting Spring only because that's what I have experience with. This tutorial gives a good intro to Spring: https://spring.io/guides/gs/rest-service/

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176282132 .

Troy Chuinard, CPA

Troy Chuinard, CPA

patflynn commented 8 years ago

Why not?

On Thu, Jan 28, 2016 at 7:27 PM, troy21688 notifications@github.com wrote:

So just to confirm, the AsyncTask Servlet Github example will not service multiple clients. For instance, if I have 1,000 users using my application (1,000 different clients), I cannot call the same .execute() method for each client?

On Thu, Jan 28, 2016 at 10:58 AM, akerekes notifications@github.com wrote:

Another disclaimer: I'm suggesting Spring only because that's what I have experience with. This tutorial gives a good intro to Spring: https://spring.io/guides/gs/rest-service/

— Reply to this email directly or view it on GitHub < https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176282132

.

Troy Chuinard, CPA

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176495398 .

troy21688 commented 8 years ago

I am referring to @akerekes response:

To handle different request from various clients is out of scope of this tutorial. To do it there are several options:

you can create multiple servlets and they will be mapped to different urls (as MyServlet is mapped to the /hello postfix) you can use one of the many server side frameworks to handle the mapping of urls to server-side logic, e.g. Spring MVC not recommended but still available option is to include a parameter into the request sent to the server (e.g. request type) and based on the value you can decide in doPost() what to do.

patflynn commented 8 years ago

Hi there,

Technically speaking, a single servlet can do as much, or as little, as you want it to do.

You probably want to look around for assistance on servlet or endpoints and app engine programming on Stack Overflow http://stackoverflow.com/questions/tagged/servlets to answer these kinds of questions. You'll find better answers there then on this project's issue tracker.

On Thu, Jan 28, 2016 at 9:45 PM, troy21688 notifications@github.com wrote:

Also, I am trying to find out how I would add multiple servlets to the same project so that I could have the server perform different functions, as previously mentioned. I take it that each servlet has to perform a different function (i.e. change a text value, set a boolean). From my understanding, one servlet cannot handle multiple tasks.

If so, please confirm this information. I appreciate your assistance!

On Thu, Jan 28, 2016 at 6:26 PM, Troy Chuinard tccpg288@gmail.com wrote:

So just to confirm, the AsyncTask Servlet Github example will not service multiple clients. For instance, if I have 1,000 users using my application (1,000 different clients), I cannot call the same .execute() method for each client?

On Thu, Jan 28, 2016 at 10:58 AM, akerekes notifications@github.com wrote:

Another disclaimer: I'm suggesting Spring only because that's what I have experience with. This tutorial gives a good intro to Spring: https://spring.io/guides/gs/rest-service/

— Reply to this email directly or view it on GitHub < https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176282132

.

Troy Chuinard, CPA

Troy Chuinard, CPA

— Reply to this email directly or view it on GitHub https://github.com/GoogleCloudPlatform/gradle-appengine-templates/issues/63#issuecomment-176540601 .

troy21688 commented 8 years ago

Thanks, what I am basically trying to do is have a server perform various functions for several clients. It sounds like for each function/task/method I want to perform, I need to create a new servlet (do I need to create a new module in App Engine for each method)? I thought one servlet could handle multiple methods, but it looks like each servlet provides its own unique response. Am I correct with this assumption?