Getting connected from an Android app to Toodledo API v3 works.
So, I know that I have a valid access_token (and refresh token).
GET requests work.
How can I add a folder ... using a POST request?
The code is below ... it keeps on spinning for new access tokens.
HttpResponse response = null;
JSONObject folderJS;
try {
Credential cred = flow.loadCredential( userId);
String apiCallUrl = "https://api.toodledo.com/3/folders/add.php";
GenericData data = new GenericData();
data.put( "name", folderName);
data.put( "private", "1");
// data.put( "access_token", accessToken); <== this is wrong
JsonHttpContent httpContent = new JsonHttpContent(new JacksonFactory(), data);
response = HTTP_TRANSPORT.createRequestFactory( cred).buildPostRequest(
new GenericUrl( apiCallUrl), httpContent).execute();
The problem was:
data.put( "access_token", accessToken);
When you add this line you get errors in processing the request. So, user error.
Related
I've a Ionic v3 application, and when I build it on a android device, all the Http GET request work, but when a POST request is launch, I've got a CORS error...
That's my request:
//Headers
let headers = new HttpHeaders();
headers = headers.append('Content-Type', 'application/json');
//Post data
let post_data = {
my_body: blabla
};
this.http.post(ENV.API_URL + 'test/test', post_data, {headers: headers}).subscribe((data: any) => {
})
If anyone can help me?
i am trying to sign a http request to aws api gateway in android using okhttp. i have more or less used the code in this stackoverflow question stackoverflow question
i use CognitoCachingCredentialsProvider() to get a credentialsProvider object. i then use getCredentials() to get the credentials. i then use the following: credentials.getAWSAccessKeyId(), credentials.getAWSSecretKey() and credentials.getSessionToken() to get the necessary keys and token. i use them in postman and am able to successfully execute the api gateway.
the request fails in android using okhttp, returning a code 403 with the message "Missing Authentication Token".
this is how i prepare the request: i build a DefaultRequest object, setting the endpoint and httpmethod. i then use AWS4Signer to sign the request, passing the credentials object as the signer.sign(defaultRequest, credentials) parameter.
i get a map of headers by calling getHeaders() on the defaultRequest. i create two lists, one called key for the key and one called value for the value. i then loop through the map, loading the keys and corresponding values into the two lists.
i then build my okhttp request as follows:
Request request = new Request.Builder()
.url(my ApiEndPoint)
.addHeader(key.get(0), value.get(0))
.addHeader(key.get(1), value.get(1))
.addHeader(key.get(2), value.get(2))
.addHeader(key.get(3), value.get(3))
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.post(body)
.build();
i notice the following:
in the headers map, key x-amz-security-token has a value ....ending in hKADF87VZ44w9IvZ1gU=
printing out the okhttp request, the key x-amz-security-token has a value .... ending in hKADF87VZ44w9IvZ1gU\u003d
the = is replaced by \u003d, could this be the problem? if so, how to prevent this?
otherwise, any help in solving this problem will be greatly appreciated.
thanks
managed to solve the problem. seems that assigning the headers to the OkHttp request was the problem. so here's my code:
i first get AWSSessionCredentials credentials. then:
AmazonWebServiceRequest amazonWebServiceRequest = new AmazonWebServiceRequest() {
};
String API_GATEWAY_SERVICE_NAME = "execute-api";
com.amazonaws.Request requestAws = new DefaultRequest(amazonWebServiceRequest, API_GATEWAY_SERVICE_NAME);
you can use either the service endpoint:
URI uri = URI.create("https://apigateway.eu-west-1.amazonaws.com");
or your api url (the invoke url for api as per Api Gateway console Stages option (The deployed api)):
String invokeUrl = "https://xxxx.execute-api.eu-west-1.amazonaws.com/yyy/zzzzz";
// using the invoke url
URI uri = URI.create(invokeUrl);
requestAws.setEndpoint(uri);
requestAws.setResourcePath(invokeUrl);
requestAws.setHttpMethod(HttpMethodName.POST);
now sign the request
AWS4Signer signer = new AWS4Signer();
signer.setServiceName(API_GATEWAY_SERVICE_NAME);
signer.setRegionName(Region.getRegion(Regions.EU_WEST_1).getName());
signer.sign(requestAws, credentials);
get the headers
// get map of headers
Map<String, String> headers = requestAws.getHeaders();
// create objects for the headers to add manually in OkHttp request builder
String x_date = null;
String x_token = null;
String authorization = null;
//get and assign values
for (Map.Entry<String, String> entry : headers.entrySet()) {
if (entry.getKey().equals("x-amz-security-token")) {
x_token = entry.getValue();
}
if (entry.getKey().equals("X-Amz-Date")) {
x_date = entry.getValue();
}
if (entry.getKey().equals("Authorization")) {
authorization = entry.getValue();
}
}
build the OkHttp request:
Request request = new Request.Builder()
.url(invokeUrl)
.addHeader("Content-Type", "application/json")
.addHeader("X-Amz-Date", x_date)
.addHeader("x-amz-security-token", x_token)
.addHeader("Authorization", authorization)
.post(body)
.build();
now make your OkHttp call.
hope this is helpful to someone.
I am asking this question based on the answers in this link
POST request via RestTemplate in JSON
I actually wanted to send JSON from client and receive the same at REST server. Since the client part is done in the link I mentioned above. For the same how would I handle that request at server end.
CLIENT:
// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
.exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
}
SERVER:
#RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(#RequestBody HttpEntity<String> entity) {
JSONObject jsonObject = new JSONObject(entity.getBody());
String username = jsonObject.getString("username");
return new ResponseEntity<>(username, HttpStatus.OK);
}
This gives me 400 bad request error at client side. Hoping for some clues about how to handle this at server side.
HTTPEntity should not be used in your server method. Instead use the argument which is being passed to HTTPEntity from your client. In your case it has to String since you are passing string from client. Below code should work for you.
#RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(#RequestBody String jsonStr) {
System.out.println("jsonStr " + jsonStr);
JSONObject jsonObject = new JSONObject(jsonStr);
String username = jsonObject.getString("username");
return new ResponseEntity<String>(username, HttpStatus.OK);
}
My advice is to create bean class and use it in server and client instead of converting it to String. It will improve readability of the code.
When using the Spring RestTemplate, I usually prefer to exchange objects directly. For example:
Step 1: Declare and define a data holder class
class User {
private String username;
private String password;
... accessor methods, constructors, etc. ...
}
Step 2: Send objects of this class to the server using RestTemplate
... You have a RestTemplate instance to send data to the server ...
// You have an object to send to the server, such as:
User user = new User("user", "secret");
// Set HTTP headers for an error-free exchange with the server.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Generate an HTTP request payload.
HttpEntity<User> request = new HttpEntity<User>(user, headers);
// Send the payload to the server.
restTemplate.exchange("[url]", [HttpMethod], request, User.class);
Step 3: Configure a ContentNegotiatingViewResolver on the server
Declare a bean of the type ContentNegotiatingViewResolver in the Spring XML or Java configuration. This will help the server automatically bind HTTP requests with bean objects.
Step 4: Receive the request on the server
#RestController
#RequestMapping("/user")
class UserAPI {
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public User create(User user) {
// Process the user.
// Possibly return the same user, although anything can be returned.
return user;
}
}
The ContentNegotiatingViewResolver ensures that the incoming request gets translated into a User instance without any other intervention.
Step 5: Receive the response on the client
// Receive the response.
HttpEntity<User> response = restTemplate.exchange("[url]", [HttpMethod], request, User.class);
// Unwrap the object from the response.
user = response.getBody();
You will notice that the client and the server both use the same bean class (User). This keeps both in sync as any breaking change in the bean structure would immediately cause a compilation failure for one or both, necessitating a fix before the code is deployed.
I am working at the REST API for a new Social Network Android App at the moment using Spring Android for the Client and Spring Boot for the Server.
I am having trouble securing the Server using Spring Security, because i don't understand how to use it properly. After reading tons of sample apps i gave up on spring security and found this tutorial on how to secure APIs using Jersey.
Instead of javascript i am using the Jersey Client API to test the implementation
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/demo-business-resource/login");
Invocation.Builder invoBuilder = target.request();
invoBuilder.header("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("username", "username2");
formData.add( "password", "passwordForUser2");
Response response = invoBuilder.post(Entity.form(formData));
System.out.println(response);
response.getEntity();
The POST request is successful, but i cant get the JSON object which should be the Entity of the Response. response.getEntity(); returns a HttpUrlConnector Object.
Here the related Server Code
#POST
#Path( "login" )
#Produces( MediaType.APPLICATION_JSON )
public Response login(
#Context HttpHeaders httpHeaders,
#FormParam( "username" ) String username,
#FormParam( "password" ) String password ) {
DemoAuthenticator demoAuthenticator = DemoAuthenticator.getInstance();
String serviceKey = httpHeaders.getHeaderString( DemoHTTPHeaderNames.SERVICE_KEY );
try {
String authToken = demoAuthenticator.login( serviceKey, username, password );
JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();
jsonObjBuilder.add( "auth_token", authToken );
JsonObject jsonObj = jsonObjBuilder.build();
return getNoCacheResponseBuilder( Response.Status.OK ).entity( jsonObj.toString() ).build();
} catch ( final LoginException ex ) {
JsonObjectBuilder jsonObjBuilder = Json.createObjectBuilder();
jsonObjBuilder.add( "message", "Problem matching service key, username and password" );
JsonObject jsonObj = jsonObjBuilder.build();
return getNoCacheResponseBuilder( Response.Status.UNAUTHORIZED ).entity( jsonObj.toString() ).build();
}
}
private Response.ResponseBuilder getNoCacheResponseBuilder( Response.Status status ) {
CacheControl cc = new CacheControl();
cc.setNoCache( true );
cc.setMaxAge( -1 );
cc.setMustRevalidate( true );
return Response.status( status ).cacheControl( cc );
}
I am new to Jersey and i only want to use it to generate the Authentication Token, because i get 404 Not Found errors using Spring. (I am working with spring-jersery )
Here my Spring approach of the client
RestTemplate template = new RestTemplate();
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
MultiValueMap<String,String> formData=new LinkedMultiValueMap<String,String>();
formData.add("username", "username2");
formData.add( "password", "passwordForUser2");
Model_LoginProfile log = new Model_LoginProfile();
log.setLoginName("username2");
log.setPassword("passwordForUser2");
HttpHeaders requestHeaders=new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.set("service_key", "3b91cab8-926f-49b6-ba00-920bcf934c2a");
HttpEntity<Model_LoginProfile> requestEntity = new HttpEntity<Model_LoginProfile>(log, requestHeaders);
ResponseEntity<String> result = template.postForEntity("http://localhost:8080/demo-business-resource/login", requestEntity, String.class);
}
Maybe someone has a fix for that as well. :)
Thanks in advance
I'm using the following snippet to request the friendslist of the authorized user:
System.out.println("AT: " + facebook.getAccessToken());
String response = facebook.request("me/friends?fields=first_name,last_name,id,gender");
The response I get:
{"error":{"message":"An active access token must be used to query information about the current user.","type":"OAuthException","code":2500}}
I'm printing the accesstoken, this gives me a valid token. Also, getAccessExpires() returns a time in the future. When I request the url "me/friends" without any params, I get the expected (but with less data) friends list without errors.
How can I solve this?
String response = facebook.request("me/friends?fields=first_name,last_name,id,gender");
That is the incorrect way to use facebook.request. I'm assuming you're not using the beta Android SDK so the correct way to do this is to do the following:
Facebook facebook = new Facebook(YOUR_APP_ID);
AsyncFacebookRunner mAsyncRunner = new AsyncFacebookRunner(facebook);
Bundle params = new Bundle();
params.put("fields", "first_name, last_name, id, gender");
mAsyncRunner.request("me/friends", params, new RequestListener() {
// get response here
....
});
Hope this helps.