Document the requests package.

This commit is contained in:
Danila Fedorin 2020-05-13 15:41:50 -07:00
parent 5d0ec6738d
commit ce0096d94f
7 changed files with 83 additions and 0 deletions

View File

@ -3,6 +3,20 @@ package com.danilafe.fencelessgrazing.requests
import com.android.volley.Response import com.android.volley.Response
import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.StringRequest
/**
* General request aimed at a protected endpoint of the API. The [token] can be retrieved
* via a [LoginRequest], or, if you've made it past the login screen, via Shared Preferences.
*
* The [AuthenticatedRequest] expects to receive a string from the API endpoint; how this string
* is handled is determined by the [Response.Listener] object. One may use
* [Response.Listener.toGsonListener] to create a JSON deserializer that expects a [String].
*
* @param baseUrl the API URL base (for example, `https://dev.danilafe.com`)
* @param apiEndpoint the API endpoint to which the request is being made.
* @param token the API token used for authentication.
* @param listener the listener object called if a valid response is received.
* @param error the error listener for the request.
*/
open class AuthenticatedRequest( open class AuthenticatedRequest(
baseUrl: String, baseUrl: String,
apiEndpoint: String, apiEndpoint: String,

View File

@ -7,6 +7,16 @@ import com.danilafe.fencelessgrazing.model.CollarPos
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
/**
* Request to the `/collars/<id>/details` API endpoint. Retrieves detailed information
* about a single collar, stored in a [CollarDetails] object.
*
* @param baseUrl the base URL of the API.
* @param collarId the identifier of the collar whose details are being retrieved.
* @param token the API token for authentication.
* @param listener the listener that will be called if a valid list of collar details is received.
* @param error the error listener for the request.
*/
class CollarDetailRequest( class CollarDetailRequest(
baseUrl: String, baseUrl: String,
collarId: Int, collarId: Int,

View File

@ -6,6 +6,17 @@ import com.danilafe.fencelessgrazing.model.CollarPos
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
/**
* A request to the `/collars/<id>/history` API endpoint. Retrieves the entire list
* of coordinates, represented as [CollarPos] objects, that the collar has transmitted.
* The coordinates are sorted by date.
*
* @param baseUrl the base URL of the API.
* @param collarId the identifier of the collar whose history is being retrieved.
* @param token the API token for authentication.
* @param listener the listener that will be called if a valid list of coordinates is received.
* @param error the error listener for the request.
*/
class CollarHistoryRequest( class CollarHistoryRequest(
baseUrl: String, baseUrl: String,
collarId: Int, collarId: Int,

View File

@ -5,6 +5,15 @@ import com.android.volley.toolbox.StringRequest
import com.danilafe.fencelessgrazing.model.CollarSummary import com.danilafe.fencelessgrazing.model.CollarSummary
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
/**
* A request to the `/collars` API endpoint. Retrieves a list of collar summaries, represented
* as [CollarSummary] objects.
*
* @param baseUrl the base URL of the API.
* @param token the API token for authentication.
* @param listener the listener that will be called if a valid list of coordinates is received.
* @param error the error listener for the request.
*/
class CollarRequest( class CollarRequest(
baseUrl: String, baseUrl: String,
token : String, token : String,

View File

@ -5,6 +5,16 @@ import com.android.volley.Response
import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.StringRequest
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
/**
* A request to the `/collars/stats/distance` API endpoint. Retrieves
* a list of [CollarDistance] objects, containing, among other things, the total
* distance traveled by each animal.
*
* @param baseUrl the base URL of the API.
* @param token the API token for authentication.
* @param listener the listener that will be called if a valid list of distances is received.
* @param error the error listener for the request.
*/
class DistanceTraveledRequest( class DistanceTraveledRequest(
baseUrl: String, baseUrl: String,
token : String, token : String,

View File

@ -6,6 +6,17 @@ import com.google.gson.Gson
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type import java.lang.reflect.Type
/**
* It appears as though a type parameter, even on that's `reified`, is erased when an anonymous
* object is declared inside an `inline` function. This means that [Gson] serialization with
* a [TypeToken] created inside this anonymous object wil _still_ fail, even though the
* surrounding function is `inline` and with a `reified` type. To work around this,
* we create the type in the function itself, and pass it as an argument to this
* [GsonListener].
*
* @param listener the underlying listener expecting a value of type [T].
* @param type the type to which [Gson] should deserialize the expected string.
*/
class GsonListener<T>(val listener: Response.Listener<T>, private val type: Type) : Response.Listener<String> { class GsonListener<T>(val listener: Response.Listener<T>, private val type: Type) : Response.Listener<String> {
override fun onResponse(response: String?) { override fun onResponse(response: String?) {
val transformed = response?.let { Gson().fromJson<T>(it, type) } val transformed = response?.let { Gson().fromJson<T>(it, type) }
@ -13,6 +24,14 @@ class GsonListener<T>(val listener: Response.Listener<T>, private val type: Type
} }
} }
/**
* Converts a [Response.Listener] of an arbitrary type [T] to a listener of type [String].
* This is done by converting the input [String] into [T] via [Gson].
* This function must be reified to prevent type erasure.
*
* @receiver the listener that will be called when the [String] is converted into [T].
* @return the resulting [String]-based listener.
*/
inline fun <reified T> Response.Listener<T>.toGsonListener(): Response.Listener<String> { inline fun <reified T> Response.Listener<T>.toGsonListener(): Response.Listener<String> {
return GsonListener(this, object : TypeToken<T>(){}.type) return GsonListener(this, object : TypeToken<T>(){}.type)
} }

View File

@ -4,6 +4,16 @@ import com.android.volley.Response
import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.StringRequest
import com.danilafe.fencelessgrazing.model.LoginResult import com.danilafe.fencelessgrazing.model.LoginResult
/**
* A request to the `/login` endpoint of the API, intended to retrieve the JWT authentication
* token to be used for the remainder of the interaction with the API.
*
* @param baseUrl the base URL of the API.
* @param username the username with which to attempt to authenticate.
* @param password the password with which to attempt to authenticate.
* @param listener the listener that will be called if authentication succeeds.
* @param error the error listener for the request.
*/
class LoginRequest( class LoginRequest(
baseUrl: String, baseUrl: String,
private val username: String, private val username: String,