I use retrofit2
in my android apps for any http/rest call. Now I need to call an api generated with Amazon AWS API Gateway.
The AWS documentation say I
It took me several days to figure out how to make it work. Don't know why they don't point out the class instead of dozen of document pages. There are 4 steps in total, you must call in worker thread, I am using Rxjava but you can use AsyncTask instead:
Observable.create((Observable.OnSubscribe<String>) subscriber -> {
//Step 1: Get credential, ask server team for Identity pool id and regions
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
this, // Context
"Identity Pool ID", // Identity Pool ID
Regions.US_EAST_1 // Region
);
//Step 2: Get these 3 three keys, test with postman v4.9.3 to see if identity is correct
String identityId = credentialsProvider.getIdentityId();
Log.show("identityId = " + identityId);
String AccessKey = credentialsProvider.getCredentials().getAWSAccessKeyId();
String SecretKey = credentialsProvider.getCredentials().getAWSSecretKey();
String SessionKey = credentialsProvider.getCredentials().getSessionToken();
Log.show("AccessKey = " + AccessKey);
Log.show("SecretKey = " + SecretKey);
Log.show("SessionKey = " + SessionKey);
//Step 3: Create an aws requets and sign by using AWS4Signer class
AmazonWebServiceRequest amazonWebServiceRequest = new AmazonWebServiceRequest() {
};
ClientConfiguration clientConfiguration = new ClientConfiguration();
String API_GATEWAY_SERVICE_NAME = "execute-api";
Request request = new DefaultRequest(amazonWebServiceRequest,API_GATEWAY_SERVICE_NAME);
request.setEndpoint(URI.create("YOUR_URI"));
request.setHttpMethod(HttpMethodName.GET);
AWS4Signer signer = new AWS4Signer();
signer.setServiceName(API_GATEWAY_SERVICE_NAME);
signer.setRegionName(Region.getRegion(Regions.US_EAST_1).getName());
signer.sign(request, credentialsProvider.getCredentials());
Log.show("Request header " + request.getHeaders().toString());
//Step 4: Create new request with authorization headers
OkHttpClient httpClient = new OkHttpClient();
Map<String, String> headers = request.getHeaders();
List<String> key = new ArrayList<String>();
List<String> value = new ArrayList<String>();
for (Map.Entry<String, String> entry : headers.entrySet())
{
key.add(entry.getKey());
value.add(entry.getValue());
}
try {
okhttp3.Request request2 = new okhttp3.Request.Builder()
.url("Your_url") // remember to add / to the end of the url, otherwise the signature will be different
.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")
.build();
Response response = null;
response = httpClient.newCall(request2).execute();
String body = response.body().string();
Log.show("response " + body);
} catch (Exception e) {
Log.show("error " + e);
}
subscriber.onNext(identityId);
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Log.show("Throwable = " + e.getMessage());
}
@Override
public void onNext(String s) {
}
});
The key here is the AWS4Signer class does 4 steps as documented here, you don't need to build one from scratch. In order to use AWS4Signer and AmazonWebServiceRequest, you need to import aws sdk in gradle:
compile 'com.amazonaws:aws-android-sdk-cognito:2.3.9'
The signature process is documented here: http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
But you could probably try to reuse some of the code from the core runtime package that the default API Gateway client depends on. There may be libraries out there already for signing requests of type RxJava or OkHttp since the signature process is well-known.
Created an OkHttp interceptor based on @thanhbinh84 answer. Give it a try: https://github.com/Ghedeon/AwsInterceptor