In my quest to learn Kotlin I am trying to write an Android app that will take 3 photos and upload them in binary format to my database via an API.
Thanks to the help of people here and the Google documentation, I have been able to get my 3 photos and display a nice thumbnail image for each one. I have also worked out how to save the image to a physical file. I don't want to physically save the file first (not least because I'd still have to upload it to the database somehow). What I'm struggling with though is (a) converting the file to binary and (b) calling an API.
I get the file(s) into a variable using:
val imageBitmap = data?.extras?.get("data") as Bitmap
This is within:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
So, at this point I have a variable (imageBitmap) which is holding the photo. My API;
http://api.domain.com/api/photos?key={APIkey}&ipaddress=1.1.1.1&activity=new&imgdate=2021-05-04&img=x0x0x0x0x0
is structured as above (img is the aspect that I need to pass the photo image through). Is it as simple as:
urlString = "http://api.domain.com/api/photos?key={APIkey}&ipaddress=1.1.1.1&activity=new&imgdate=2021-05-04&img=" + imageBitmap
Would the above not be invalidly trying to concatenate a string and an object?
The API is written in C# through Visual Studio and calls a stored proc in my database. The img parameter in the proc is varbinary(max) so base64 encoded.
I found a lot of references to using OKHttp3, but I can't find an example that is clear enough for a beginner. What I was envisaging was that I'd call a function that encompasses the call and returns the json response. I took the code below from an example, and whilst it doesn't error, it doesn't make a call either:
fun doAPICall(url: String, body: String): String {
val apiClient = OKHttpClient()
var resp: String = ""
val request = Request.Builder().url(url).build()
//Define the body if present
apiClient.newCall(request).enqueue(object: Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) {
resp = response.body()?.string()!!
}
})
}
So, I have two problems that I'm struggling to understand here. Firstly how do I convert imageBitmap into a binary string that I can pass in the API as a part of the url parameter, and secondly, how do I call the API and get the response back?
I tried a very simple example to see if the code worked by just calling an API and trying to write the response value to a TextView:
txtResponse.text = doAPICall("http://api.domain.com/api/photos?key={APIkey}&ipaddress=1.1.1.1&activity=getName", "")
This doesn't throw an error, but doesn't put the response into the textview either. The response for this should be:
{
"APIResult": [
{
"id": 200,
"status_message": "Success",
"name": "Testing"
}
]
}
Can someone provide some pointers for me please?
Related
I'm trying to make handling database data easier in an app that I am creating.
This is the object being used to upload the data to Firebase. This is also the object I want to convert the data back into to be used by the app's interface:
class WYRQuestionDBModel(var side1Question: String,
var side2Question : String,
var side1Count : Int,
var side2Count : Int)
So far I am getting this result:
{side2Question=empty, side2Count=1, side1Count=1, side1Question=empty}
How can I convert this back to the object above in Kotlin?
Here is the function that I ma trying to achieve this in:
Firebase.database.reference.child(Constants.wyrDBQuestionLocation)
.child(randQuestionId.toString())
.get()
.addOnFailureListener { task ->
Log.i("Get WYR Question Status", "Failed: " + task.message.toString())
//All values remain the same
}.addOnSuccessListener {
Log.i("Get WYR Question Status", "Success")
Log.i("Request Data Result", it.value.toString())
dataRequestResult = it.value.toString()
//Convert the data to an object here
Log.i("Database Result", dataRequestResult.toString())
}
Did you see the Firebase documentation on reading and writing data? The Post class in there should be a pretty direct template for your WYRQuestionDBModel class.
If you follow the pattern outline in those docs, reading a `` can be done with:
val question = it.value.getValue<WYRQuestionDBModel >()
Note: be sure to include the -ktx extensions version of the SDK.
I am calling a post API with some parameters. one the parameters is
activatecode="aaaaaa$rr"
when the API call is made, it is sent as
activatecode=aaaaaa%24rr
The $ is encoded as %24. How to avoid this and send the special character as it is?
I am using Retrofit 2.9.0.
I have this service :
interface WordpressService {
#GET("wp-json/wp/v2/posts")
suspend fun getPosts(
#Query("page") page: Int,
#Query("per_page") limit: Int,
#Query("_fields", encoded = true) fields: String = "date,link,title,content,excerpt,author"
): List<Post>
}
Without putting encode = true, I end up with this request :
GET http://example.org/wp-json/wp/v2/posts?page=1&per_page=10&_fields=date%2Clink%2Ctitle%2Ccontent%2Cexcerpt%2Cauthor
With encode = true, I get :
GET http://motspirituel.org/wp-json/wp/v2/posts?page=1&per_page=10&_fields=date,link,title,content,excerpt,author
So in my case, adding encode = true in annotation solved my problem.
In my application I should upload image to server.
For server requests I used retrofit 2
I write upload codes, but show me error for validation and say me media field is empty.
Upload image request from PostMan : Click to see image
In postman everything is ok and not any problem and image upload successfully!
But in my code show me validation error!
My api interface code :
#Multipart
#POST("media/")
fun uploadImage(
#Header(AUTHORIZATION) auth: String, #Header(ACCEPT) accept: String, #Header(CONTENT_TYPE) contentType: String,
#Part media: MultipartBody.Part
): Single<Response<ResponseModelUploadImage>>
Upload image code :
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
photoEasy.onActivityResult(
requestCode, resultCode
) { thumbnail ->
val imgFile = bitmapToFile(thumbnail, "myImageNameIsThisTest.jpeg")
Log.e("filePath",imgFile.toString())
val reqFile = RequestBody.create(MediaType.parse("multipart/form-data"), imgFile)
val filePart = MultipartBody.Part.createFormData("media", imgFile?.name, reqFile)
presenter.callUploadImage(userToken, APPLICATION_JSON, APPLICATION_JSON, filePart)
}
}
How can I fix it?
URL
This is an example of an upload function in an Android app (in Kotlin) that sends a picture to a server (in this case is a web application developed with Java and Spring Boot) with Retrofit as multipart/form-data:
private suspend fun sendPicture(sessionId: UUID, p: Picture): Boolean {
try {
val data_part = p.data.toRequestBody("multipart/form-data".toMediaTypeOrNull())
val data_multi_part =
MultipartBody.Part.createFormData("picture", p.description, data_part)
val sessionId_part =
sessionId.toString().toRequestBody("multipart/form-data".toMediaTypeOrNull())
val id_part = p.id.toString().toRequestBody("multipart/form-data".toMediaTypeOrNull())
val categoryId_part =
p.categoryId?.toString()?.toRequestBody("multipart/form-data".toMediaTypeOrNull())
val response = api.sendPicture(sessionId_part, id_part, categoryId_part, data_multi_part)
if (!response.isSuccessful) {
#Suppress("BlockingMethodInNonBlockingContext")
val msg = response.errorBody()?.string() ?: textHelper(
R.string.error_send_picture,
p.id.toString()
)
Logger.trace(EventCode.SerializationError, msg, EventSeverity.Error)
}
return response.isSuccessful
} catch (e: Exception) {
Logger.trace(p, EventCode.SerializationError, e.localizedMessage, Action.Send, EventSeverity.Exception)
}
return false
}
And the generated API that uses Retrofit 2.6 is declared as follows:
#Multipart
#POST("SendPicture")
suspend fun sendPicture(#Part("sessionId") sessionId: RequestBody, #Part("pictureId") id: RequestBody, #Part("categoryId") categoryId: RequestBody?, #Part picture: MultipartBody.Part): Response<Void>
Take into account that Picture is an Android Room (ORM) entity and p.data it's the image representation as a byte array (val data: ByteArray).
sessionId = is a session ID (it's just a custom value of type UUID)
pictureId = is the ID of the picture (type: UUID)
categoryId = is the ID of the category the picture belongs to (type: UUID)
These 3 values are custom (you don't need them), they are there just to show how to pass more data to the server together with the image.
The function is written in Kotlin.
I think you have everything you need to extract the code that better suits your needs. This example is taken from the code of a project of mine and it was tested. It sends pictures stored in the local database to the server.
You can easily port the code to Java.
I use the Apollo Android library to make queries to a GraphQL endpoint.
Everything works OK until I try to convert the results back to JSON strings (to store them in a Room database). I naively tried to use Moshi, however this fails with the following error:
Cannot get available extra products: No JsonAdapter for interface com.example.MyQuery$MyFragmentInterface
where MyFragmentInterface in an interface generated by Apollo to handle query fragments.
So, I tried to find whether the Apollo library has/generates any conversion methods, i.e. sth like toJson()/fromJson(), for the generated models, however I couldn't find anything usable.
Am I missing something obvious?
Since Apollo 1.3.x there is an Operation.Data.toJson() extension function (Kotlin) and a corresponding serialize static method in Java.
Check https://www.apollographql.com/docs/android/advanced/no-runtime/#converting-querydata-back-to-json
For the opposite, Json string to Query.Data, I use something like the following:
fun String?.toMyData(): MyQuery.Data? {
this ?: return null
val query = MyQuery()
val response: Response<MyQuery.Data> =
OperationResponseParser(query,
query.responseFieldMapper(),
ScalarTypeAdapters.DEFAULT)
.parse(Buffer().writeUtf8(this))
return response.data
}
Here is an example how you can deserialize string as generated object. Inlined comments for further details.
// Sample string response
val jsonResponse = """
{
"data": {
{
"id": "isbn-889-333",
"title": "Awesome title",
"rating": 5
}
}
""".trimIndent()
// Create query that is expect to return above response
val query = QueryBookDetails("book_id")
// convert string to input stream
val inputStream = ByteArrayInputStream(jsonResponse.toByteArray())
// Read bytes into okio buffer
val buffer = Buffer().readFrom(inputStream)
// Use the query to parse the buffer.
val response = query.parse(buffer)
// response.data might be the one needed by you
Bear in mind that the response must honour the schema.
Try Postman and see if the error also appears there https://blog.getpostman.com/2019/06/18/postman-v7-2-supports-graphql/
New to using API's (and kotlin for that matter) and I'm having some trouble figuring out how to pull data from an API into model objects and was hoping someone could point me in the right direction. Sample code below.
val request = Request.Builder().header("X-Mashape-Key", keyVal).url(url).build()
//make request client
val client = OkHttpClient()
//create request
client.newCall(request).enqueue(object: Callback {
override fun onResponse(call: Call?, response: Response?) {
//grab as string, works fine
val body = response?.body()?.string()
//make my builder, works fine
val gson = GsonBuilder().create()
// to pass type of class to kotlin ::
val cardFeed = gson.fromJson(body, CardFeed::class.java)
}
override fun onFailure(call: Call?, e: IOException?) {
println("Failed to execute request")
}
})
}
All of that seems to work as intended in debug, I get the string, and can see it but using the following it still dumps a null into the cardFeed/cards object.
class CardFeed(val cards: List<Card>)
class Card(val cardId: String, val name: String, val text: String, val flavor: String)
The body string I'm getting from the API reads as follows
body: "{Basic":[{"key":"value", etc
I'm assuming the [ is what's tripping me up, but not sure how to correct it.
Any ideas or nudges in the correct direction would be greatly appreciated and thanks ahead of time.
According to your class structure, the JSON object that you should get from the API should be
{
"cards":[
{
"cardId":"<cardID>",
"name":"<name>",
"flavor":"<flavor>"
},
{
"cardId":"<cardID>",
"name":"<name>",
"flavor":"<flavor>"
}
]
}
with the correct keys because when you use gson.fromJson(body, CardFeed::class.java), it looks for the variable names in the class assigned (CardFeed.java). If you don't have the correct keys ("cards", "cardId", "name", "flavor"), gson would return null for the values
okHttp is a low level library. In order to consume JSON based APIs, Retrofit is a much more suitable library, as it already have converters that use libraries like GSON or Moshi to do all the heavy lifting for you.