I've been using okhttp's mock web server (https://github.com/square/okhttp/tree/master/mockwebserver) in testing for quite a bit now and it works really well. From reading the documentation and browsing Google, it seems the library is really targeted for testing.
My question though is whether there is any reason why I couldn't use this in production code? I have an android app that I am working on that requires the need for a mock web server. I've integrated it and it is working fine but I am concerned whether there is something completely wrong with what I am doing.
Also, are there any security risks that I should be aware of when using mock web server in production?
Thanks!
The MockWebServer returns "mock" (in other words, "not real") data. If you used the class in production, you would have to either continue providing fake data to it, or make real HTTP calls through some separate library or tool and stuff its responses into the MockWebServer. And then, what would be the point? Why not just let OkHttp make the calls directly as it was designed?
My guess is you might be misunderstanding the relationship between OkHttp3 and MockWebServer.
OkHttp3 - HTTP client that makes HTTP requests over any HTTP stack (by default, uses the supplied Android device HTTP network; wi-fi, cell, etc.)
MockWebServer - only used in tests to supply hard-coded (not real) HTTP responses to an OkHttp HTTP client so that a live network connection is not needed during the tests, or to consistently simulate various network connection issues such as dropped connections, invalid HTTP responses, server errors, etc.
You should only be using OkHttp3 in your application code.
In your tests only, you have MockWebServer to fake responses (or intercept if you configure it that way) to test out your application's calls to OkHttp3. When you go to production, none of the MockWebServer code should ever be referenced or called (since you put it all in the test/androidTest source code directories, right?) and the OkHttp3 code would make real HTTP calls over the internet since MockWebServer won't be there to intercept them anymore.
Basically, if you have anything in your build.gradle other than testCompile 'com.squareup.okhttp3:mockwebserver:x.x.x' and/or androidTestCompile 'com.squareup.okhttp3:mockwebserver:x.x.x' than you're doing it wrong. The main, real, production application has no need for a mock web server since it will be making real calls over the internet to a real web server.
Related
I'm currently working on a library that enables QA or Developers debug network traffic in their app, we currently use OKHttp and I know how to create an interceptor and dispatch all request data to the lib. such that Developers or QA can view such data (Payload/URL/Size/Response Codes/Duration...etc), however I want to create a more generic solution that listens to HTTP traffic or even TCP traffic then take it from there, however I couldn't find a starting point, I know that this is possible since Firebase Performance is doing it, but still I couldn't find an API or anyway to listen to such traffic.
I hope that someone from Google's Firebase Performance Team shares some info about how they do it if it's not a trade-secret :)
I came across this solution: https://github.com/cyruliu/Sensitive_API_Monitor/blob/master/app/src/main/java/com/android/reverse/apimonitor/NetWorkHook.java
However it looks kinda bad with reflection, I hope to find a better way.
The short answer: It's not possible without proxying the whole device.
For OkHttp3 specifically I wrote a lib here: https://github.com/shehabic/sherlock that implements an interceptor that creates a new session every time your open your app and captures network requests, you can also have multiple session, it adds a floating icon that helps you access sessions and requests' history as well as some export capabilities, additionally it adds a secondary launcher icon that you can use to access the captures requests without interrupting the app's process.
Regarding Firebase Performance, all the magic is actually in the Firebase-Perf Gradle plugin; to simplify it, it scans through the project's code and replaces direct calls to OkHttpClient to be be proxied through their own FirebaseOkHttpClient and from there they get all the details even for https request as they become the http client.
I hope that this saves someone some time in the future.
The current solution that I have to adopt uses JDBC and stores the user/password of the database inside the android app. That's as far as I'm concerned not a good solution. I would like to implement a mapping layer on the webserver in the middle.
Is there any best practice or recommended strategy for this? Should I use SOAP or JSON or something completely different (because they're well implemented and/or easy to use in Java)?
Are there any mapping tools for postgresql <-> SOAP/JSON/whatever in PHP or will I need to write these scripts by myself?
Any pointers will be greatly appreciated.
Quick version:
Use a web service midlayer running on a public host you control (possibly but not necessarily the database host). Expose public web service methods to do the limited work you want to permit and nothing else.
Related questions:
Driver JDBC PostgreSQL with Android
How to connect to a PostgreSQL server via JDBC in Android?
Implementation options
Personally I'd use a Java application server like Apache Tomcat or JBoss AS 7 and I'd write my web service methods using JAX-RS to produce a nice REST-style API for my app to use. That's what I'm familiar with and it works well, but you have lots of options including implementations of:
REST-like APIs (Java's JAX-RS impls Jersey and RESTEasy, various other langs tools) that use HTTP requests and produce JSON or XML replies.
SOAP with WSDL, the classic "web service" layer. In Java done with JAX-WS among other options. Most languages have tools for SOAP+WSDL but it's kind of crappy to work with especially on intermittently connected devices like mobiles.
XML-RPC if you like pain
There are some JAX-RS quickstarts on the JBoss AS 7 quickstarts list; just search for "JAX-RS". The "kitchen sink" quickstart is useful, though perhaps not ideal if you're not familiar with the basics of JBoss AS 7 and Jave EE 6. Fort the JAX-RS specifics you're better off with a Jersey or RESTEasy tutorial like this or this.
Important considerations
Use HTTPs if possible, and if access isn't to be public use a suitable HTTP authentication scheme like HTTP Basic auth over HTTPs. Any decent web services implementation will offer authentication options or support those of the platform on which it runs. Avoid the temptation to implement your own authentication and user management at the web services layer, you will screw it up; use the auth at the HTTP layer that's already written and tested. This may require the use of something like Apache's mod_auth_pgsql, JBoss AS 7's JDBC security realms, etc. The only case I'd consider not doing proper per-user HTTP auth is where I don't need to separate my users for security reasons, I only care that it's my app accessing the server, ie if my security requirements are quite weak. In this case I'd use a fixed username/password for the whole app and possibly an X.509 client certificate if Android supports them.
Remember that no matter how you secure things, all credentials are either known to the user or can be extracted trivially from a .apk so you still have to assume anybody could access your web service methods, not just your app. Write them accordingly.
Do not just send SQL from your app over a web service call to the server and return the results as JSON. This is horrifyingly insecure, as well as ugly and clunky. Write a web service method for each individual task you want the app to be able to perform and keep the SQL in the server. Remember to use parameterised queries and be careful of other SQL injection risks. These web service methods may use one or more queries to produce a single reply - for example, you might collect a "Customer" record and all associated "Address" and "Contact" records then return the result in a nice JSON object the Android device can consume, saving numerous slow and unreliable network round trips.
No matter what you use, make sure to do your web service calls in a background worker thread and not to block the user interface. Be prepared for timeouts and errors, and for the need for retries. Test your app by simulating intermittent connection loss, high latency, and high rates of packet loss and make sure it remains usable.
Is there a best practise:
It depends on the person. All have their strength and weakness.
I prefer, and I think many but not all will agree on JSON cause it is really easy to use in Android. It's also lightweight and very easy to use in php. Php has methods to convert an array/object to json and back.
It is indeed not recommended to save your postgres data on an android device.
My strategy is usually:
PHP server side with a POSTGRESQL database, using PDO to communicate between my models and the database.
If you are not familiar with PDO(php data objects), I recommend you make yourself familiar with it.
php.net PDO
Android as client, using JSON as method of transfering data from and to.
There are many examples that can help you.
Android has standard libraries to handle json parsing.
See this answer for an example:
example
I'm current using Restlet to interface with an Android app.
I want the Restlet on the server to then trigger a C2DM push message when it gets a certain POST from an Android app - it's basically just a simple HTTP POST to Google's servers with some extra values in it.
I imagine there must be some way of using the in built connector, or otherwise, anyone have any ideas? Can't seem to find anything about it on the net, an unusual request perhaps.
Edit: Probably should have expanded on this to begin with, the reason why I ask is that I'm trying to use Apache httpClient inside the restlet but I'm not able to to get it to work. If that is what you're supposed to do, then it's probably a different question altogether.
Use Java's native HttpURLConnection object: http://download.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html
Follow the implementation guidelines provided by Google: http://code.google.com/android/c2dm/#push
So what I was doing is the right way to do it after all, I've got Apache HttpClient set up and working in a seperate thread to do the push. For some reason it fails due to a peer exception (which is the exception I was getting initially), but I've got around that by automatically trusting the SSL certificate. Why that was happening with the C2DM address I really have no idea.
This is not really a problem, more like a general X vs. Y question.
So I'm experimenting with c2dm on android using a server written in google app engine. At the moment I'm using the "App Engine Connected Android Project" as a template with some added code myself. So the generated code use RequestFactory for a bunch of stuff, like registering/unregistering devices, sending messages, etc.
My previous experiences with backend communication has existed of setting up a connection to a servlet, writing to it (json) and reading the response (json).
So here's the question:
What are the benefits (if any) with using the RequestFactory for communication with the app engine instead of just writing/reading from an URLConnection's input/outputstreams?
Or is it really just a matter of taste?
One disadvantage of request factory is that it is very slow in retrieving objects.. A custom servlet and http request are MUCH faster(10x-20x faster!).
Check out this post for more details RequestFactory slow on Android
I haven't used it myself yet, but the main benefit, as I understand it, is that it makes it really easy to authenticate against the App Engine app with your Android credentials. Doing that by hand is a bit of a pain.
I'm writing an Android app which sometimes needs to request data through HTTP from a REST API. I'm using the Apache DefaultHttpClient for performing requests. Is there a way to write tests for this app and "replace" DefaultHttpClient's response when running the tests so that test results are always consistent?
As an example of the things I'd like to test, one of the web services I'm accessing takes a string and performs a text search, returning a paged list of objects. I need to test the cases where the list is empty, the list fits in the first page, or the list is larger than a page and the app needs to make several requests to get the complete list.
I'm not the developer of this web API nor can modify its responses, so I can't change what it returns. For the above example, if I want to test the case where the list returned is empty, I could just search for a string which I'm sure won't return any results, but the other two cases are harder because what the service can return is always changing.
I think ideally I would have a way to get a modified DefaultHttpClient when running tests, that returns a hardcoded result for requests to a given URL instead of actually doing the network request. This way I would always get consistent results independently of the real web service's response.
I'm currently using Robotium for testing but I'm open to using other tools too.
Yes, you can definitely "fake" responses when using the HttpClient framework. It's quite convoluted, and I will have to leave most of the details up to you, but I will give you a quick overview:
Implement ClientHttpRequestFactory, mainly so you can override the createRequest() method so you can...
Return your custom implementation of ClientHttpRequest, in which you can override the execute() method so you can ...
Return your custom implementation of ClientHttpResponse in which you will finally be able to return your fake response data, e.g. getBody() can return the content of a file, you can hardcode the headers in getHeaders(), etc.
The rest is figuring out how to best tie all these shenanigans to your service layer.
You might give Charles a try for something like this. Sorta a non-code solution.
http://www.charlesproxy.com/
I use the Charles' reverse proxies and the map local tool for things like this.
What you do is point your request at your local box on the reverse proxy port. Charles in turn can be configured to provide a static hard-coded flat file but to your app it looks like a 100% genuine web service response.
There are lots of other cool things you can do with Charles - watch traffic from your android app to and from your server and breakpoints (which allows you to tweak requests and responses before they are sent and received). Definitely worth checking out.
Another option is to use Dependency Injection so that you can change the HttpClient when running the tests. Check out Guice if you are interested.
I'm guessing you are interested in writing functional tests using the standard Android Junit testing framework. So you could just implement the parts of the API you are using on your own webserver and point at that server when running your tests.
If you'd prefer your tests to be self-contained, you could implement an Http server that runs on the device. Examples of using the Http server available in the Android class library are here and here.