Kotlin & Retrofit: Simple POST without Response - rest

I'm trying to do a POST Request with Kotlin and Retrofit where I'm only interested in the statuscode of the request. Tutorials I have seen solve it all a bit different and most of the time they do not compile any more or are very complicated.
Can someone help improving this code:?
interface ClientService {
#POST("user/password-reset")
fun passwortReset(#Query("email") email: String): Observable<Result>
companion object {
fun create(): ClientService {
val retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://test-backend.myurl.com/api/")
.build()
return retrofit.create(ClientService::class.java)
}
}
}
I'm not sure how to call it and how to get the statuscode.

Try this example
Under build.gradle:
// retrofit
compile "com.squareup.retrofit2:retrofit:2.3.0"
compile "com.squareup.retrofit2:adapter-rxjava2:2.3.0"
compile "com.squareup.retrofit2:converter-gson:2.3.0"
// rxandroid
compile "io.reactivex.rxjava2:rxandroid:2.0.1"
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
Interface:
interface APIService {
#POST("register")
#FormUrlEncoded
fun registrationPost(#Field("email") email: String,
#Field("password") password: String): Call<Registration>}
//**App Utils**
object ApiUtils {
val BASE_URL = "your_url"
val apiService: APIService
get() = RetrofitClient.getClient(BASE_URL)!!.create(APIService::class.java)
}
Retrofit Client:
object RetrofitClient {
var retrofit: Retrofit? = null
fun getClient(baseUrl: String): Retrofit? {
if (retrofit == null) {
//TODO While release in Google Play Change the Level to NONE
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(100, TimeUnit.SECONDS)
.readTimeout(100, TimeUnit.SECONDS)
.build()
retrofit = Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
}
MainActivity
//Variable declaration
var mAPIService: APIService? = null
//After oncreate
mAPIService = ApiUtils.apiService
//Some Button click
mAPIService!!.registrationPost("SampleTest2#gamil.com", "123456").enqueue(object : Callback<Registration> {
override fun onResponse(call: Call<Registration>, response: Response<Registration>) {
Log.i("", "post submitted to API." + response.body()!!)
if (response.isSuccessful()) {
Log.i("", "post registration to API" + response.body()!!.toString())
Log.i("", "post status to API" + response.body()!!.status)
Log.i("", "post msg to API" + response.body()!!.messages)
}
}
override fun onFailure(call: Call<Registration>, t: Throwable) {
}
})

Inside any function you have to call like:
fun resetPassword(email:String) {
val clientService = ClientService.create(APIConstants
.BASE_URL_WORKSPACE)
addSubscription(apiService.login(APIConstants.API_ACTION_LOGIN, userName, password,
deviceid), object : APICallback<UserLoginResponse>() {
override fun onSuccess(model: UserLoginResponse) {
if (TextUtils.isEmpty(model.errorMessage)) {
mvpView.getDataSuccess(model, apiRequestCode)
} else {
mvpView.getDataFail(model.errorMessage, apiRequestCode)
}
}
override fun onFailure(msg: String?) {
LogUtil.e("Login Failure()- " + msg!!)
}
override fun onFinish() {}
})
}
You will get the success response/result in onSuccess() method.

There is lot's of answers for the same question. Main Funda is to Call Post API using Retrofit.
Let me make some easier things to call Any API.
In this Example of code. i used Demo API from https://jsonplaceholder.typicode.com/
First takes Permission in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
Now go create one interface for Post API Response.
interface ApiInterFace {
#POST("users")
fun sendUserData(#Body userPost: UserPost) : Call<UserPost>
}
Now Comes to MainActivity or your Target Activity to call the API.
in this method i used static dummy data for user.
private fun sendDataToApi() {
val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://jsonplaceholder.typicode.com/") // Add Your BaseUrl here
.build()
val jsonPlaceHolder = retrofitBuilder.create(ApiInterFace::class.java)
val userPost = UserPost(1,1,"New Added","Body of the title") // Dummy Data
val call = jsonPlaceHolder.sendUserData(userPost)
call.enqueue(object : Callback<UserPost>{
override fun onResponse(call: Call<UserPost>, response: Response<UserPost>) {
Log.e("TAG", "onResponse: "+response.code() )
}
override fun onFailure(call: Call<UserPost>, t: Throwable) {
Log.e("TAG", "onFailure: "+t.message )
}
} )
}
This is only based on simple example of Post the data to server. There MayBe having changes as per your cases.

Related

How to store Set<Granted Authority> for JWT Authentication correctly in PostgreSQL

I am trying to implement Jwt Authentication with user role and permission-based authentification.
While my user gets authenticated, the returned list of authorities during debugging is always empty and not what ist supposed to be, a list of the user's GrantedAuthority. Also during debugging it shows me the following message
Expecting an element; looking at ERROR_ELEMENT '(1,53) in /fragment.kt
I watched several Java Tutorials and tried to translate them to Kotlin and apart from showing an empty List of Granted Authorities so far it is working.
Here are my code snippets.
Entity User
#Table(name = "users")
#Entity
data class User(
...
#Transient
private val grantedAuthorities: Set<GrantedAuthority>,
...
) : UserDetails {...}
Role
enum class Role (private val permissions: Set<Permissions>) {
PRIMARY_OWNER(
Sets.newHashSet(
VIEW_FILES,
...
private fun getPermissions(): Set<Permissions> {
return permissions
}
fun getGrantedAuthorities(): Set<SimpleGrantedAuthority> {
val permissions = getPermissions().stream()
.map { permission: Permissions ->
SimpleGrantedAuthority(
permission.getPermission()
)
}
.collect(Collectors.toSet())
permissions.add(SimpleGrantedAuthority("ROLE_$name"))
return permissions
}
Permissions
enum class Permissions(private val permission: String) {
// File Management
VIEW_FILES("files:view"),
...
fun getPermission(): String {
return permission
}
}
JwtUsernameAndPasswordAuthenticationFilter
class JwtUsernameAndPasswordAuthenticationFilter(private val jwtAuthenticationManager: AuthenticationManager) :
UsernamePasswordAuthenticationFilter() {
override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse): Authentication {
try {
val authenticationRequest =
ObjectMapper().readValue(request.inputStream, UsernameAndPasswordAuthenticationRequest::class.java)
val authentication = UsernamePasswordAuthenticationToken(
authenticationRequest.username,
authenticationRequest.password
)
val authenticate = jwtAuthenticationManager.authenticate(authentication)
return authenticate
} catch (e: Exception) {
throw RuntimeException(e)
}
}
override fun successfulAuthentication(
request: HttpServletRequest,
response: HttpServletResponse,
chain: FilterChain,
authResult: Authentication
) {
val key = "blablabla"
val token = Jwts.builder()
.setSubject(authResult.name)
.claim("authorities", authResult.authorities)
.setIssuedAt(java.util.Date())
.setExpiration(Date.valueOf(LocalDate.now().plusWeeks(2)))
.signWith(Keys.hmacShaKeyFor(key.toByteArray()))
.compact()
response.addHeader("Authorization", "Bearer $token")
}
}
My best guess is, that I store them wrong, that's why they are not showing but I am not sure and really do not know the best way to fix it.

How to get custom header from response (retrofit & rxjava)

I am trying to get some custom HTTP headers from all the REST API responses in my code.
Here is how I initiate the client:
private fun initializeClient(): OkHttpClient {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
val httpClient = OkHttpClient.Builder()
.addInterceptor(object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
val request = original.newBuilder()
.header("Content-Type", "application/json")
.method(original.method, original.body)
.build()
return chain.proceed(request)
}
})
.addInterceptor(interceptor)
.build()
return httpClient
}
private fun initializeApi() {
api = Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(initializeClient())
.build()
.create(RestApi::class.java)
}
Here is a sample of the retrofit implementation:
#POST("/register")
fun registerUser(#Body registerPostData: RegistrationForm): Single<RegistrationResponse>
and the ViewModel part:
disposable.add(
api.registerUser(form)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableSingleObserver<Member>() {
override fun onSuccess(value: RegistrationResponse?) {
// no headers in here
response.value = value
}
override fun onError(e: Throwable?) {
}
})
)
The server returns some x-custom-header in all API responses, which I need to capture in all calls.
Thank you!
Change your retrofit class to return a Response:
#POST("/register")
fun registerUser(#Body registerPostData: RegistrationForm): Single<Response<RegistrationResponse>>
then:
override fun onSuccess(result: Response<RegistrationResponse>?) {
// get header from response.headers()
}

Netty wss socket client drops connection

Trying to setup basic wss client. Channel is activated, but then immediately disconnected without any exception.
Client:
class WebSocketClient(val uri: String) {
lateinit var ch: Channel
fun connect() {
val bootstrap = Bootstrap()
val uri: URI = URI.create(uri)
val handler = WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, false, HttpHeaders.EMPTY_HEADERS, 1280000))
bootstrap.group(NioEventLoopGroup())
.channel(NioSocketChannel::class.java)
.handler(object : ChannelInitializer<SocketChannel>() {
override fun initChannel(ch: SocketChannel) {
val pipeline = ch.pipeline()
pipeline.addLast("http-codec", HttpClientCodec())
pipeline.addLast("aggregator", HttpObjectAggregator(65536))
pipeline.addLast("ws-handler", handler)
}
})
ch = bootstrap.connect(uri.host, 443).sync().channel()
handler.channelPromise.sync()
}
}
Handler:
class WebSocketClientHandler(val handShaker: WebSocketClientHandshaker) : SimpleChannelInboundHandler<Any>() {
lateinit var channelPromise: ChannelPromise
override fun handlerAdded(ctx: ChannelHandlerContext) {
channelPromise = ctx.newPromise()
}
override fun channelActive(ctx: ChannelHandlerContext) {
handShaker.handshake(ctx.channel())
}
override fun channelRead0(ctx: ChannelHandlerContext, msg: Any) {
val ch = ctx.channel()
if (!handShaker.isHandshakeComplete) {
handShaker.finishHandshake(ch, msg as FullHttpResponse)
channelPromise.setSuccess()
return
}
val frame = msg as WebSocketFrame
if (frame is TextWebSocketFrame) {
println("text message: $frame")
} else if (frame is PongWebSocketFrame) {
println("pont message")
} else if (frame is CloseWebSocketFrame) {
ch.close()
} else {
println("unhandled frame: $frame")
}
}
}
The flow of handler calls:
handleAdded
channelRegistered
channelActive
channelReadComplete
channelInactive
channelUnregistered
handlerRemoved
Is there something I miss?
You forgot to add a SSLHandler, this handler is needed because you are connecting to the https port (443), so the remote server expects all the traffic to be encrypted. Sending a unencrypted message to the https port has undefined behaviour, some server will shut down your connection, other servers will send a redirect back to https.
You can add an sslhandler using the following way:
java:
final SslContext sslCtx = SslContextBuilder.forClient()
// .trustManager(InsecureTrustManagerFactory.INSTANCE)
.build();
pipeline.addLast("ssl-handler", sslCtx.newHandler(ch.alloc(), url.getHost(), 443));
// Your remaining code....
pipeline.addLast("http-codec", new HttpClientCodec())

Capture exception thrown in prototype (Typescript)

Excellent Angular 2/Material Design framework, Teradata Covalent, provides a RESTService abstract class that wraps REST api calls here:
https://teradata.github.io/covalent/#/components/http
Code to incorporate the extension is easy, as follows:
export class CustomRESTService extends RESTService<any> {
constructor(private _http: Http /* or HttpInterceptorService */) {
super(_http, {
baseUrl: 'www.api.com',
path: '/path/to/endpoint',
headers: new Headers(),
dynamicHeaders: () => new Headers(),
transform: (res: Response): any => res.json(),
});
}
}
The "update" method in the RESTService abstract class is shown here:
public update(id: string | number, obj: T, transform?: IRestTransform): Observable<any> {
let requestOptions: RequestOptionsArgs = this.buildRequestOptions();
let request: Observable<Response> = this.http.patch(this.buildUrl(id), obj, requestOptions);
return request.map((res: Response) => {
if (res.status === 200) {
if (transform) {
return transform(res);
}
return this.transform(res);
} else {
return res;
}
}).catch((error: Response) => {
return new Observable<any>((subscriber: Subscriber<any>) => {
try {
subscriber.error(this.transform(error));
} catch (err) {
subscriber.error(error);
}
});
});
}
My question is: if the update method of the abstract class throws an exception, how can that be captured in the CustomRESTService class? I.e., what Typescript code might one use to display an error in the UI?
Thank you.
First thing's first - Why would you want to catch it inside the rest client and not inside the app's logic?
Assuming you have some good reason for doing that (some other infrastructure code that you're running in the CustomRESTClient class), I would override the update function and implement error handling there.
A simple example without observables:
abstract class Base {
update(n:number):number {
return n;
}
test():bool;
}
class Child extends Base {
update(n:number):number {
return super.update(n)*2;
}
test():bool {
return true;
}
}

How to create Custom Directive by composing multiple directives in spray

I would like to write a custom directive for all get, post,put and delete requests, because all requests needs authorization. To keep code DRY, I want to abstract those boilerplate(I have to authorize more than 100 requests). I could handle all Get Requests as follows
def method1 = Try("hi") // controller methods
def method2 = Try("hello")
path("getData1") {
handleGetRequest(method1)
}
path("getData2") {
handleGetRequest(method2)
}
def customGetDirective: Directive0 = {
headerValueByName("token").flatMap { token =>
authorize(checkAuthorization(token, ""))
get.hflatMap {x=>
respondWithMediaType(`application/json`)
}
}
}
def handleGetRequest(fn: => Try[_]) = {
customGetDirective { ctx=>
val result = fn
val json = //result can be coverted to json
ctx.complete(json)
}
}
I want to write a similar Generic directive for POST request, so that I could use
path("postData1") {
handlePostRequest(saveToDb)
}
def handlePostRequest(fn: => Try[_]) = {
customPostDirective { (ctx, JsonData)=>
//.......
ctx.complete(json)
}
}
but, I dont know how to get RequestContext and JsonData as tuple
I can write like this,
entity(as[String]) { jsonData =>
customPostDirective{ ctx=>
}
}
If I get a tuple it will be more useful.
Thank you.