Post body raw json to server retrofit 2? - retrofit

I have a rest web service on a server with postman. How can I send this request to the service?
Body->Raw->JSON(application/json)
[{"NewDigit":"0070297","ReadingStatus":"1","WaterMeterStatus":"1","SCode":"113950","ReportedIssues":"","LNG":"0.0","LAT":"0.0"}]
And this is my Header on the Postman:
Authorization:bearer 123 Content-Type:application/json
and server return this to me:
"OK"
Now I want to implement that with retrofit. This is my interface:
public interface IPostReads {
#Headers( "Content-Type: application/json")
#POST("/readings")
Call<String> savePost(#Header("Authorization") String Authorization, #Body RequestBody body);
}
And this:
public class PostReading {
private PostReading() {}
public static final String BASE_URL = "http://185.113.58.156:9100/";
public static IPostReads getAPIService() {
return RetrofitClient.getClient(BASE_URL).create(IPostReads.class);
}
}
I have the following code for the post request:
String[] parts = params[0].toString().split(";");
ir.behineh.wepapiinterface.PostReadingToServer.IPostReads taskService = ServiceGenerator.createService(ir.behineh.wepapiinterface.PostReadingToServer.IPostReads.class);
Call<String> tasks = taskService.savePost("bearer "+parts[1].toString(),RequestBody.create(MediaType.parse("application/json"),parts[0].toString()));
try {
String x=tasks.execute().body();
Log.d("behzad post output:",x.toString());
} catch (IOException e) {
e.printStackTrace();
}
I get a response with code 200, but the server returns an error. I think there is something wrong in the body parameter.
What happens?
Thanks.

Remove / from #POST("/readings") => #POST("readings") because you already added it on base url at the end.

Related

How does Unity receive http request?

I want to accept http request to order prefab move, so how to receive http request in unity 3D?
If you mean you want to build a web service in your Unity app.
RESTful-Unity is an easy-to-use plugin.
Define the api routing
RoutingManager routingManager = new RoutingManager();
routingManager.AddRoute(new Route(Route.Type.POST, "/path/to/call", "PrefabInvoke.Move"));
Create an Invoke to response the request
namespace RESTfulHTTPServer.src.invoker
{
public class PrefabInvoke : MonoBehaviour
{
public static Response Move(Request request)
{
Response response = new Response();
string responseData = "";
string json = request.GetPOSTData();
bool valid = true;
UnityInvoker.ExecuteOnMainThread.Enqueue (() => {
Debug.Log(json);
try
{
//TODO: Parse Json string and do somthing
response.SetHTTPStatusCode((int)HttpStatusCode.OK);
responseData = "sucess message";
}
catch (Exception ex)
{
valid = false;
string msg = "failed to deseiralised JSON";
responseData = msg;
}
});
// Wait for the main thread
while (responseData.Equals("")) {}
// Filling up the response with data
if (valid) {
// 200 - OK
response.SetContent(responseData);
response.SetHTTPStatusCode ((int)HttpStatusCode.OK);
response.SetMimeType (Response.MIME_CONTENT_TYPE_JSON);
} else {
// 406 - Not acceptable
response.SetContent("Somthing wrong");
response.SetHTTPStatusCode((int) HttpStatusCode.NotAcceptable);
response.SetMimeType(Response.MIME_CONTENT_TYPE_HTML);
}
return response;
}
}
}

Slack-Integration in ASP.NET Web-Api 2

I want to know exactly why this is not working:
[HttpPost]
public IHttpActionResult Post(Slack_Webhook json)
{
return Ok(json.challenge);
}
public class Slack_Webhook
{
public string type { get; set; }
public string token { get; set; }
public string challenge { get; set; }
}
The Official Documentation says:
We’ll send HTTP POST requests to this URL when events occur. As soon
as you enter a URL, we’ll send a request with a challenge parameter,
and your endpoint must respond with the challenge value.
This is an example object (JSON) sent by Slack:
{
"token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
"challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
"type": "url_verification"
}
EDIT:
I could write a book on code that does not work in this issue... here's another example that did not work - still no idea what is wrong:
[HttpPost]
public IHttpActionResult Post()
{
var pairs = Request.GetQueryNameValuePairs();
bool isValidToken = false;
string c = "This does not work.";
foreach(var pair in pairs)
{
if (pair.Key == "token")
{
if (pair.Value == "<UNIQUETOKEN>")
{
isValidToken = true;
}
}
if (pair.Key == "challenge")
{
c = pair.Value;
}
}
if (isValidToken == true)
{
return Json(new {challenge = c });
}
else
{
return BadRequest();
}
}
EDIT2:
Very interesting that I get NULL as a response from below code - that means the body of the received POST is empty.. Could anyone with a working Slack-Integration try that out? So their site is wrong, stating the challenge is sent in the body - where else could it be?
// POST: api/Slack
[HttpPost]
public IHttpActionResult Post([FromBody]string json)
{
return Json(json);
}
EDIT3:
This function is used to get the raw request, but there is nothing inside the body - I am out of solutions.. the support of Slack said, they have no idea about ASP.NET and I should ask here on SO for a solution. Here we are again! ;-)
[HttpPost]
public async Task<IHttpActionResult> ReceivePostAsync()
{
string rawpostdata = await RawContentReader.Read(this.Request);
return Json(new StringContent( rawpostdata));
}
public class RawContentReader
{
public static async Task<string> Read(HttpRequestMessage req)
{
using (var contentStream = await req.Content.ReadAsStreamAsync())
{
contentStream.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(contentStream))
{
return sr.ReadToEnd();
}
}
}
}
The result ( as expected ) looks like this:
Our Request:
POST
"body": {
"type": "url_verification",
"token": "<token>",
"challenge": "<challenge>"
}
Your Response:
"code": 200
"error": "challenge_failed"
"body": {
{"Headers":[{"Key":"Content-Type","Value":["text/plain; charset=utf-8"]}]}
}
I think I'm missing something - is there another way to get the body of the POST-Request? I mean, I can get everything else - except the body ( or it says it is empty).
EDIT4:
I tried to read the body with another function I found - without success, returns empty string - but to let you know what I already tried, here it is:
[HttpPost]
public IHttpActionResult ReceivePost()
{
var bodyStream = new
StreamReader(HttpContext.Current.Request.InputStream);
bodyStream.BaseStream.Seek(0, SeekOrigin.Begin);
var bodyText = bodyStream.ReadToEnd();
return Json(bodyText);
}
While trying to solve this I learnt a lot - but this one seems to be so impossible, that I think I will never solve it alone. Thousands of tries with thousands of different functions - I have tried hundreds of parameters and functions in all of WebApi / ASP.NET / MVC / whatever - why is there no BODY? Does it exist? What's his/her name? Where does it live? I really wanna hang out with that parameter if I ever find it, must be hidden at the end of the rainbow under a pot of gold.
If you can use ASP.NET Core 2, this will do the trick:
public async Task<ActionResult> HandleEvent([FromBody] dynamic data)
=> new ContentResult {Content = data.challenge};
According to the official documentation linked to in the OP you have to format your response depending on the content type you return.
It is possible you are not returning the value (challenge) in one of the expected formats.
Once you receive the event, respond in plaintext with the challenge
attribute value. In this example, that might be:
HTTP 200 OK
Content-type: text/plain
3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P
To do the above you would have needed to return your request differently
[HttpPost]
public IHttpActionResult Post([FromBody]Slack_Webhook json) {
//Please verify that the token value found in the payload
//matches your application's configured Slack token.
if (ModelState.IsValid && json != null && ValidToken(json.token)) {
var response = Request.CreateResponse(HttpStatusCode.OK, json.challenge, "text/plain");
return ResponseMessage(response);
}
return BadRequest();
}
Documentation also shows
Or even JSON:
HTTP 200 OK
Content-type: application/json
{"challenge":"3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P"}
Which again would have to be formatted a little differently
[HttpPost]
public IHttpActionResult Post([FromBody]Slack_Webhook json) {
//Please verify that the token value found in the payload
//matches your application's configured Slack token.
if (ModelState.IsValid && json != null && ValidToken(json.token)) {
var model = new { challenge = json.challenge };
return Ok(model);
}
return BadRequest();
}
Here's how you can access the data:
[HttpPost]
[Route("something")]
public JsonResult DoSomething()
{
var token = HttpContext.Request.Form["token"];
// Is the same as:
// var token = Request.Form["token"];
return new JsonResult(token);
}
I suggest using a Request Bin for further debugging.

How can I get dynamic response when using Spring Cloud Contract?

org.springframework.cloud.contract.spec.Contract.make {
request {
method 'GET'
url '/weather'
}
response {
status 200
body([
"weather": value(regex("(SUNNY|WINDY|CLOUDY|RAINY)"))
])
}
I know Groovy DSL is able to generate a random value, Like the code above.
But the Groovy DSL just generate a static stub, and it will always return the same response as I requested.
How can I get a random weather without re-generate the stubs in this case?
You can't, that's because WireMock stub needs a concrete value on the response side. The only thing you could do is to reference the request from the response and then the request can have random input. In general, your tests shouldn't depend on random response.
I know is an old question but I found a workaround solution to achieve that using dynamic values from the given request, you can set a custom headers using $regex then use as output response.
Groovy
request {
method 'GET'
url """/v1/persons/${anyUuid()}"""
headers {
contentType('application/json')
header 'Authorization' : 'Mocked Return Data'
header 'nameMocked' : $(regex('[a-zA-Z0-9]{5, 30}'))
header 'dateMocked' : $(regex('(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/([0-9]{4})'))
header 'typeMocked' : $(regex('CONSUMER|COMMERCIAL'))
}
}
response {
status 200
body(
"""
{
"name": "${fromRequest().header('nameMocked')}",
"date": "${fromRequest().header('dateMocked')}",
"type": "${fromRequest().header('typeMocked')}",
}
"""
)
headers {
contentType('application/json')
}
}
BaseClass
class PersonDto {
private UUID id;
private String name;
private LocalDate date;
private PersonType type;
}
#Slf4j
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = JacksonAutoConfiguration.class)
public abstract class BaseTest {
#Autowired
private ObjectMapper objectMapper;
#Before
public void setup() throws Exception {
YourController yourController = spy(new YourController());
//normal business mocks
doAnswer((Answer<ResponseEntity>) invocation -> {
HttpServletRequest currentRequest = getCurrentRequest();
Map<String, String> map = Collections.list(currentRequest.getHeaderNames()).stream()
.filter(n -> n.endsWith("Mocked"))
.collect(Collectors.toMap(k -> k.replaceFirst("Mocked", ""), currentRequest::getHeader));
return ResponseEntity.ok(objectMapper.convertValue(map, PersonDto.class)); //Convert map to dto
}).when(YourController).getPerson(matches("([a-f0-9]{8}(-[a-f0-9]{4}){4}[a-f0-9]{8})"), eq("Mocked Return Data")); //This should match your request
RestAssuredMockMvc.standaloneSetup(yourController);
}
private HttpServletRequest getCurrentRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
Assert.state(requestAttributes != null, "Could not find current request via RequestContextHolder");
Assert.isInstanceOf(ServletRequestAttributes.class, requestAttributes);
HttpServletRequest servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
Assert.state(servletRequest != null, "Could not find current HttpServletRequest");
return servletRequest;
}
}
Consumer example
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
#AutoConfigureStubRunner(workOffline = true, ids = "groupId:artifactId:+:stubs:8083")
#DirtiesContext
public class ConsumerContractAT {
#Test
public void callApiGetShouldReturnDynamicMockedData() {
Response response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Mocked Return Data")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header("nameMocked", "Test")
.header("typeMocked", "CONSUMER")
.header("dobMocked", DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.of(2019, 10, 10)))
.when()
.get("/v1/persons/{tokeId}", UUID.randomUUID())
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("typeMocked")).isEqualTo("CONSUMER");
assertThat(response.jsonPath().getString("name")).isEqualTo("Test");
assertThat(response.jsonPath().getString("dob")).isEqualTo("10/10/2019");
response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Mocked Return Data")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header("nameMocked", "Test 2")
.header("typeMocked", "COMMERCIAL")
.header("dobMocked", DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.now()))
.when()
.get("/v1/persons/{tokeId}", UUID.randomUUID())
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("typeMocked")).isEqualTo("COMMERCIAL");
assertThat(response.jsonPath().getString("name")).isEqualTo("Test 2");
assertThat(response.jsonPath().getString("dob")).isEqualTo(DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.now()));
}
}

How to pass header in Azure endpoint..?

I am using Azure API , URL getting below error please help on this issue. please share codesnip, how to change in web.config and endpoints.
The HTTP request is unauthorized with client authentication scheme
'Anonymous'. The authentication header received from the server was
'AzureApiManagementKey
realm="https:/azure.azure-api.net/MethodName",name="Ocp-Apim-Subscription-Key",type="header"'.
I know this is a very old question still, my answer would help someone faces the same issue.
The solution is to create a custom endpoint behavior where you add a custom message handler to the binding parameters.
In the custom message handler, please add your request headers. After this, use any of the binding technique (like basichttpsbinding or NetHttpsBinding) with security mode as "Transport" and MessageEncoding as "Text" for creating soap client object. Add custom endpoint behavior to the soap client.
public class CustomEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
bindingParameters.Add(new Func<HttpClientHandler, HttpMessageHandler>(x =>
{
return new CustomMessageHandler(x);
}));
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
public class CustomMessageHandler : DelegatingHandler
{
public CustomMessageHandler(HttpClientHandler handler)
{
InnerHandler = handler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
request.Headers.Add("xxxx", "abcde");
return base.SendAsync(request, cancellationToken);
}
}
The console app to consume the service.
static async Task Main(string[] args)
{
var client = GetSOAPClient();
try
{
var result = await client.MyOperation().ConfigureAwait(false);
if(result.Body != null && result.Body.status == "Success")
{
Console.WriteLine(result.Body.myValue);
}
}
catch (Exception ex)
{
Console.WriteLine(ex?.Message);
}
Console.ReadKey();
}
static MyServiceClient GetSOAPClient()
{
NetHttpsBinding binding = new NetHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.MessageEncoding = NetHttpMessageEncoding.Text;
EndpointAddress ea = new EndpointAddress(new Uri("https://myazureurl"));
var client = new MyServiceClient(binding, ea);
client.Endpoint.EndpointBehaviors.Add(new CustomEndpointBehavior());
return client;
}
}
This is complaining that your Subscription key is wrong. If you check the response body, it will give you a readable message of what the real problem is. Double check you are entering the correct subscription key for your Azure API access.
You get your subscription key from the Developer Portal under your profile menu. You can see an example of the subscription key being used in this article under the section "Call an operation from the developer portal": https://learn.microsoft.com/en-us/azure/api-management/api-management-get-started
Also, the 'The HTTP request is unauthorized with client authentication scheme 'Anonymous'.' part of the message is a red herring and a separate problem with how responses work.

Basic Authentication with Retrofit

I am trying to build a client for a REST API using Retrofit. The API uses basic auth and I have been unable to authenticate using Retrofit.
I tested the API using the curl below and it works as expected
curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{some_json}' -u api_key: https://apitest.com/api/v1/customers
Below is the Retrofit client
public interface UserService {
String HOST = "https://apitest.com";
public static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(HOST)
.addConverterFactory(GsonConverterFactory.create());
/*
* CREATE/UPDATE User
*/
#POST("api/v1/customers")
Call<UserAPIResponse> userUpdate(#Body UserUpdateRequest userUpdateRequest);
static UserService newInstance(String userAPIKey) {
String credentials = userAPIKey + ":";
final String basic = "Basic "+ Base64.encodeBase64(credentials.getBytes());
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic);
requestBuilder.header("Accept", "application/json");
requestBuilder.method(original.method(),original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(BlueshiftUserService.class);
}
When I call updateUser on the UserService
Response<UserAPIResponse> response = UserService.userUpdate(userUpdateRequest).execute();
The response.code is 401 (unauthorized/authentication failed)
The curl command with -u and the same credentials works as expected.
The issue was with the credentials encoding. I wasnt sending it as string.
byte[] encodedAuth= Base64.encodeBase64(credentials.getBytes());
final String basic = "Basic " + new String(encodedAuth);
use these libraries in Gradle file
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.cookpad.android.rxt4a:rxt4a:0.9.0'
compile 'io.reactivex:rxjava:1.0.12'
and put this classes in your project
public class ServiceGenerator {
private static final String TAG = erviceGenerator.class.getSimpleName();
public static final int READ_TIMEOUT = 10000;
public static final int CONNECT_TIMEOUT = 100000;
// No need to instantiate this class.
private ServiceGenerator(){}
public static <S> S createService(Class<S> serviceClass, String
endpoint) {
// Call basic auth generator method without user and pass
return createService(serviceClass, endpoint, null, null); }
public static <S> S createService(Class<S> serviceClass, String
endpoint, String username, String password) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
// Set endpoint url and use OkHTTP as HTTP client
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(endpoint)
.setConverter(new GsonConverter(new Gson()))
.setClient(new OkClient(okHttpClient));
if (username != null && password != null) {
// Concatenate username and password with colon for authentication
final String credentials = username + ":" + password;
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
// Create Base64 encoded string
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Authorization", string);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass); } }
and this interface
public class TodolyClient {
private static final String TAG = TodolyClient.class.getSimpleName();
public static final String ENDPOINT = "your base URL";
public interface TodolyService {
#GET("/wp-json/wc/v2/products")(your remaining url)
Observable<Object> isAuthenticated();
}
}
and call the below method in your main activity
private void createProject() {
final TodolyClient.TodolyService service =ServiceGenerator.createService(
TodolyClient.TodolyService.class, TodolyClient.ENDPOINT, "your user name",
"your password");
Observable<Object> observable = service.isAuthenticated();
AndroidCompositeSubscription compositeSubscription = new AndroidCompositeSubscription();
observable
.lift(new OperatorAddToCompositeSubscription<Object>(compositeSubscription))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onNext(Object project) {
android.util.Log.d(TAG, "onNext: "+project.toString());
}
#Override
public void onCompleted() {
android.util.Log.d(TAG, "onNext:commm " );
}
#Override
public void onError(Throwable e) {
android.util.Log.d(TAG, "onNext: eeeeeeeee"+e.getMessage());
}
});
}
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class), You can add any character set for encoding as the third parameter here.
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/

Resources