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

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()
}

Related

Kotlin & Retrofit: Simple POST without Response

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.

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())

Use Spring as a REST Client [duplicate]

i have to call this REST service written in scala-akka project from java-spring.
my scala REST service is like
val route =
post {
path("notification" / "signUp"){
headerValueByName("App_Key") { app_key => {
handleWith {
requestParameters: RequestParameters =>
//application specific implementation
}
}
}
}
which contains App_Key and Content-Type in header and request parameters in json format.
request parameters are like:
case class RequestParameters (
var name: String,
var email: String,
var password: String,
var hashKey: String
)
so i have to call this REST service from java spring. I an struggling while calling http://ipadress:port/notification/signUp from java .
U can call this via. Following Implementation :
try {
Client client = Client.create();
WebResource webResource = client.resource(http://ipadress:port/notification/signUp);
JSONObject formData=new JSONObject();
formData.put("name", UserName);
formData.put("email", EmailId);
formData.put("password", Password);
formData.put("urlHash",HashKey);
ClientResponse response = webResource.header("App_Key",xxxxxxxxxxxxxxxxxxxxxxxxxx).type(MediaType.APPLICATION_JSON_TYPE).post(ClientResponse.class, formData);
} catch (Exception e) {
e.printStackTrace();
}

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.

Grails RestBuilder simple POST example

I'm trying to do an OAuth2 user-credentials post to an OAuth2 service using the Grails RestBuilder plugin.
If I try to specify the post body as a map, I get an error about no message converters for LinkedHashMap.
If I try to specify the body as a String, the post goes through, but none of the variables are posted to the server action.
Here's the post:
RestBuilder rest = new RestBuilder()
def resp = rest.post("http://${hostname}/oauth/token") {
auth(clientId, clientSecret)
accept("application/json")
contentType("application/x-www-form-urlencoded")
// This results in a message converter error because it doesn't know how
// to convert a LinkedHashmap
// ["grant_type": "password", "username": username, "password": password]
// This sends the request, but username and password are null on the host
body = ("grant_type=password&username=${username}&password=${password}" as String)
}
def json = resp.json
I've also tried setting the urlVariables in the post() method call, but the username/password are still null.
This is a very simple post, but I can't seem to get it to work. Any advice would be greatly appreciated.
I solved the problem by using a MultiValue map for the body.
RestBuilder rest = new RestBuilder()
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>()
form.add("grant_type", "password")
form.add("username", username)
form.add("password", password)
def resp = rest.post("http://${hostname}/oauth/token") {
auth(clientId, clientSecret)
accept("application/json")
contentType("application/x-www-form-urlencoded")
body(form)
}
def json = resp.json
Following code works for Box connection. Spend few of hours figuring this out
String pclient_id = grailsApplication.config.ellucian.box.CLIENT_ID.toString()
String pclient_secret=grailsApplication.config.ellucian.box.CLIENT_SECRET.toString()
String pcode = params.code
log.debug("Retrieving the Box Token using following keys Client ID: ==>"+pclient_id+"<== Secret: ==>"+pclient_secret+"<== Code: ==>"+pcode)
RestBuilder rest = new RestBuilder()
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>()
form.add("client_id", pclient_id)
form.add("client_secret", pclient_secret)
form.add("grant_type", "authorization_code")
form.add("code", pcode)
def resp = rest.post("https://app.box.com/api/oauth2/token") {
accept("application/json")
contentType("application/x-www-form-urlencoded")
body(form)
}
def js = resp.json.toString()
println("sss"+js)
def slurper = new JsonSlurper()
def result = slurper.parseText(js)
println("Message:"+result.error)
render js
I found out some very easy to perform such type of action
//Get
public static RestResponse getService(String url) {
RestResponse rResponse = new RestBuilder(proxy:["localhost":8080]).get(Constants.URL+"methodName")
return rResponse
}
//POST : Send complete request as a JSONObject
public static RestResponse postService(String url,def jsonObj) {
RestResponse rResponse = new RestBuilder(proxy:["localhost":8080]).post(url) {
contentType "application/json"
json { jsonRequest = jsonObj }
}
return rResponse
}
Method 1 :
def resp = RestUtils.getService(Constants.URL+"methodName")?.json
render resp as JSON
Method 2 :
JSONObject jsonObject = new JSONObject()
jsonObject.put("params1", params.paramOne)
jsonObject.put("params2", params.paramTwo)
def resp = RestUtils.postService(Constants.URL+"methodName", jsonObject)?.json
render resp as JSON