Skip to content

Commit 2f5c8c4

Browse files
author
nphau
committed
feat: add sample for RESTful API : GET
1 parent 0e232b7 commit 2f5c8c4

File tree

21 files changed

+307
-96
lines changed

21 files changed

+307
-96
lines changed

.idea/misc.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<p align="center">
44
<a>
55
<img src="https://img.shields.io/badge/kotlin-v1.6.10-blue.svg">
6-
<img src="https://img.shields.io/badge/gradle-7.%3Cspan%20class="x x-first x-last">0.4-blueviolet.svg">
6+
<img src="https://img.shields.io/badge/gradle-7.%3Cspan%20class="x x-first x-last">1.0-blueviolet.svg">
77
<img src="https://img.shields.io/badge/API-21%2B-blue.svg?style=flat">
88
<img src="https://img.shields.io/badge/License-Apache%202.0-success.svg">
99
<img src="https://circleci.com/gh/twilio-labs/plugin-rtc.svg?style=svg">
@@ -12,13 +12,48 @@
1212

1313
[![-----------------------------------------------------](https://raw.githubusercontent.com/andreasbm/readme/master/assets/lines/colored.png)](#table-of-contents)
1414

15-
## 🚀 Copyright
15+
## 👇 Overview
16+
17+
A minimal way to create HTTP server in android with Kotlin. Create asynchronous client and server applications. Anything from microservices to multiplatform HTTP client apps in a simple way. Open Source, free, and fun!
18+
19+
```kotlin
20+
embeddedServer(Netty, PORT, watchPaths = emptyList()) {
21+
install(WebSockets)
22+
install(CallLogging)
23+
routing {
24+
get("/") {
25+
call.respondText(
26+
text = "Hello!! You are here in ${Build.MODEL}",
27+
contentType = ContentType.Text.Plain
28+
)
29+
}
30+
}
31+
}
32+
```
33+
## 🚀 How to use
34+
35+
Cloning the repository into a local directory and checkout the desired branch:
36+
37+
```
38+
git clone [email protected]:nphau/android.embeddedserver.git
39+
cd android.embeddedserver
40+
git checkout master
41+
```
42+
## 🍲 Screenshots
43+
44+
<h4 align="center">
45+
<img src="docs/device.gif" width="20%" vspace="10" hspace="10">
46+
<img src="docs/edge_get.gif" width="70%" vspace="10" hspace="10">
47+
48+
## ✨ Contributing
49+
Please feel free to contact me or make a pull request.
50+
51+
## 👀 Author
1652

1753
``` Created by $username on $today
1854
Copyright (c) $today.year . All rights reserved.
1955
Last modified $file.lastModified
2056
```
21-
## 👇 Authors
2257
<p>
2358
<a href="https://nphau.medium.com/" target="_blank">
2459
<img src="https://avatars2.githubusercontent.com/u/13111806?s=400&u=f09b6160dbbe2b7eeae0aeb0ab4efac0caad57d7&v=4" width="96" height="96">

app/build.gradle

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ plugins {
44
}
55

66
android {
7-
compileSdk 31
7+
compileSdk 32
88

99
defaultConfig {
10-
applicationId "com.imstudio.app.embeddedserver"
10+
applicationId "com.nphau.app.embeddedserver"
1111
minSdk 21
12-
targetSdk 31
12+
targetSdk 32
1313
versionCode 1
1414
versionName "1.0"
1515

@@ -30,27 +30,30 @@ android {
3030
jvmTarget = '1.8'
3131
}
3232
packagingOptions {
33-
exclude 'META-INF/*'
34-
// Due to https://github.com/Kotlin/kotlinx.coroutines/issues/2023
35-
exclude 'META-INF/licenses/*'
36-
exclude '**/attach_hotspot_windows.dll'
33+
jniLibs {
34+
excludes += ['META-INF/*', 'META-INF/licenses/*']
35+
}
36+
resources {
37+
excludes += ['META-INF/*', 'META-INF/licenses/*', '**/attach_hotspot_windows.dll']
38+
}
3739
}
3840
}
3941

4042
dependencies {
4143

4244
implementation 'androidx.core:core-ktx:1.7.0'
43-
implementation 'androidx.appcompat:appcompat:1.3.1'
44-
implementation 'com.google.android.material:material:1.4.0'
45-
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
45+
implementation 'androidx.appcompat:appcompat:1.4.1'
46+
implementation 'com.google.android.material:material:1.5.0'
47+
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
4648
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
4749
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
4850

4951
// Coroutines
50-
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
52+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
5153

5254
// Embedded Server
53-
implementation 'io.ktor:ktor-server-core:1.6.2'
55+
implementation 'io.ktor:ktor-server-core:1.6.4'
56+
implementation 'io.ktor:ktor-gson:1.6.4'
5457
implementation 'io.ktor:ktor-server-netty:1.6.2'
5558
implementation 'io.ktor:ktor-websockets:1.6.2'
5659
}

app/src/main/AndroidManifest.xml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="com.imstudio.app.embeddedserver">
3+
package="com.nphau.app.embeddedserver">
44

55
<uses-permission android:name="android.permission.INTERNET" />
66
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -15,14 +15,30 @@
1515
android:supportsRtl="true"
1616
android:theme="@style/Theme.MyApplication">
1717
<activity
18-
android:name=".MainActivity"
18+
android:name="com.nphau.app.embeddedserver.activities.MainActivity"
1919
android:exported="true">
2020
<intent-filter>
2121
<action android:name="android.intent.action.MAIN" />
2222

2323
<category android:name="android.intent.category.LAUNCHER" />
2424
</intent-filter>
2525
</activity>
26+
<provider
27+
android:name="androidx.core.content.FileProvider"
28+
android:authorities="${applicationId}.provider"
29+
android:enabled="true"
30+
android:exported="false"
31+
android:grantUriPermissions="true"
32+
android:permission="android.permission.MANAGE_DOCUMENTS">
33+
34+
<intent-filter>
35+
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
36+
</intent-filter>
37+
38+
<meta-data
39+
android:name="android.support.FILE_PROVIDER_PATHS"
40+
android:resource="@xml/file_provider_paths" />
41+
</provider>
2642
</application>
2743

2844
</manifest>

app/src/main/assets/images/file.png

4.42 MB
Loading

app/src/main/java/com/imstudio/app/embeddedserver/MainActivity.kt

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Created by nphau on 04/02/2022, 22:24
3+
* Copyright (c) 2022 . All rights reserved.
4+
* Last modified 04/02/2022, 22:23
5+
*/
6+
7+
package com.nphau.app.embeddedserver.activities
8+
9+
import android.os.Build
10+
import android.os.Bundle
11+
import android.widget.TextView
12+
import androidx.appcompat.app.AppCompatActivity
13+
import androidx.appcompat.widget.AppCompatImageView
14+
import com.nphau.app.embeddedserver.R
15+
import com.nphau.app.embeddedserver.data.BaseResponse
16+
import com.nphau.app.embeddedserver.data.Database
17+
import com.nphau.app.embeddedserver.data.models.Cart
18+
import com.nphau.app.embeddedserver.extensions.animateFlash
19+
import com.nphau.app.embeddedserver.utils.NetworkUtils
20+
import io.ktor.application.*
21+
import io.ktor.features.*
22+
import io.ktor.gson.*
23+
import io.ktor.http.*
24+
import io.ktor.response.*
25+
import io.ktor.routing.*
26+
import io.ktor.server.engine.*
27+
import io.ktor.server.netty.*
28+
import io.ktor.websocket.*
29+
import kotlinx.coroutines.CoroutineScope
30+
import kotlinx.coroutines.Dispatchers
31+
import kotlinx.coroutines.launch
32+
33+
class MainActivity : AppCompatActivity() {
34+
35+
companion object {
36+
private const val PORT = 5001
37+
}
38+
39+
private val server by lazy {
40+
embeddedServer(Netty, PORT, watchPaths = emptyList()) {
41+
install(WebSockets)
42+
install(CallLogging)
43+
// provides the automatic content conversion of requests based on theirContent-Type
44+
// and Accept headers. Together with the json() setting, this enables automatic
45+
// serialization and deserialization to and from JSON – allowing
46+
// us to delegate this tedious task to the framework.
47+
install(ContentNegotiation) {
48+
gson {
49+
setPrettyPrinting()
50+
disableHtmlEscaping()
51+
}
52+
}
53+
// configures Cross-Origin Resource Sharing. CORS is needed to make calls from arbitrary
54+
// JavaScript clients, and helps us prevent issues down the line.
55+
install(CORS) {
56+
method(HttpMethod.Get)
57+
method(HttpMethod.Post)
58+
method(HttpMethod.Delete)
59+
anyHost()
60+
}
61+
// Greatly reduces the amount of data that's needed to be sent to the client by
62+
// gzipping outgoing content when applicable.
63+
install(Compression) {
64+
gzip()
65+
}
66+
routing {
67+
get("/") {
68+
call.respondText(
69+
text = "Hello!! You are here in ${Build.MODEL}",
70+
contentType = ContentType.Text.Plain
71+
)
72+
}
73+
get("/fruits") {
74+
call.respond(HttpStatusCode.OK, BaseResponse(Cart.sample()))
75+
}
76+
get("/fruits/{id}") {
77+
val id = call.parameters["id"]
78+
val fruit = Database.FRUITS.find { it.id == id }
79+
if (fruit != null) {
80+
call.respond(HttpStatusCode.OK, BaseResponse(fruit))
81+
} else {
82+
call.respond(HttpStatusCode.NotFound)
83+
}
84+
}
85+
}
86+
}
87+
}
88+
89+
override fun onCreate(savedInstanceState: Bundle?) {
90+
super.onCreate(savedInstanceState)
91+
setContentView(R.layout.activity_main)
92+
93+
findViewById<AppCompatImageView>(R.id.image_logo).animateFlash()
94+
95+
// Show IP Address
96+
findViewById<TextView>(R.id.text_status).apply {
97+
val simpleTextApi =
98+
String.format("GET: %s:%d", NetworkUtils.getLocalIpAddress(), PORT)
99+
val apiGet =
100+
String.format("GET: %s:%d/fruits", NetworkUtils.getLocalIpAddress(), PORT)
101+
val apiGetWithId =
102+
String.format("GET: %s:%d/fruits/{id}", NetworkUtils.getLocalIpAddress(), PORT)
103+
text = String.format("%s\n%s\n%s", simpleTextApi, apiGet, apiGetWithId)
104+
//animateFlash()
105+
}
106+
107+
// Start server
108+
CoroutineScope(Dispatchers.IO).launch {
109+
server.start(wait = true)
110+
}
111+
}
112+
113+
override fun onDestroy() {
114+
server.stop(1_000, 2_000)
115+
super.onDestroy()
116+
}
117+
118+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Created by nphau on 04/02/2022, 23:02
3+
* Copyright (c) 2022 . All rights reserved.
4+
* Last modified 04/02/2022, 23:02
5+
*/
6+
7+
package com.nphau.app.embeddedserver.data
8+
9+
data class BaseResponse<T>(val data: T? = null, val error: String? = null)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Created by nphau on 04/02/2022, 23:00
3+
* Copyright (c) 2022 . All rights reserved.
4+
* Last modified 04/02/2022, 23:00
5+
*/
6+
7+
package com.nphau.app.embeddedserver.data
8+
9+
import com.nphau.app.embeddedserver.data.models.Fruit
10+
import java.util.*
11+
12+
object Database {
13+
14+
val FRUITS = listOf(
15+
Fruit(UUID.randomUUID().toString(), "Cucumbers 🥒"),
16+
Fruit(UUID.randomUUID().toString(), "Tomatoes 🍅"),
17+
Fruit(UUID.randomUUID().toString(), "Orange Juice 🍊")
18+
)
19+
20+
}

0 commit comments

Comments
 (0)