REST API
Overview
The Amplify CLI deploys REST APIs and handlers using Amazon API Gateway and AWS Lambda.
The API category will perform SDK code generation which, when used with the AWSMobileClient
can be used for creating signed requests for Amazon API Gateway when the service Authorization is set to AWS_IAM
or when using a Cognito User Pools Authorizer.
See the authentication section for more details for using the AWSMobileClient
in your application.
Set Up Your Backend
In a terminal window, navigate to your project folder (the folder that typically contains your project level build.gradle
), and add the SDK to your app.
cd YOUR_PROJECT_FOLDERamplify add api
When prompted select the following options:
> REST> Create a new Lambda function> Serverless express function> Restrict API access? Yes> Who should have access? Authenticated and Guest users
When configuration of your API is complete, the CLI displays a message confirming that you have configured local CLI metadata for this category. You can confirm this by running amplify status
. Finally deploy your changes to the cloud:
amplify push
Once the deployment completes a folder with the name of your API's resource name will be created in ./src/main/java
. This is the client SDK with the models you will import and use in the ApiClientFactory()
builder from your code in the following sections.
Connect to Your Backend
Add the following to your app/build.gradle
:
dependencies { implementation 'com.amazonaws:aws-android-sdk-apigateway-core:ANDROID_SDK_VERSION' implementation 'com.amazonaws:aws-android-sdk-mobile-client:ANDROID_SDK_VERSION' implementation 'com.amazonaws:aws-android-sdk-auth-userpools:ANDROID_SDK_VERSION'}
Build your project. Next, you will need to import the client that was generated in ./src/main/java
when you ran amplify push
. For example, an app named useamplify
with an API resource named xyz123
, the path of the code file will be ./src/main/java/xyz123/useamplifyabcdClient.java
. The API client name will be useamplifyabcdClient
. You would have the following entries in your code:
import YOUR_API_RESOURCE_NAME.YOUR_APP_NAME_XXXXClient;
private YOUR_APP_NAME_XXXXClient apiClient = new ApiClientFactory() .credentialsProvider(AWSMobileClient.getInstance()) .build(YOUR_API_CLIENT_NAME.class);
Find the resource name of your API by running amplify status
. Copy your API client name to use when invoking the API in the following sections.
IAM authorization
To invoke an API Gateway endpoint from your application, import the generated client as outlined in the last section and use the generated client class, model, and resource paths as in the below example with YOUR_API_RESOURCE_NAME.YOUR_APP_NAME_XXXXClient
, YOUR_APP_NAME_XXXXClient
, and YOUR_API_CLIENT_NAME
replaced appropriately. For AWS IAM authorization use the AWSMobileClient
as outlined in the authentication section.
import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;
import com.amazonaws.http.HttpMethodName;import com.amazonaws.mobile.client.AWSMobileClient;import com.amazonaws.mobile.client.AWSStartupHandler;import com.amazonaws.mobile.client.AWSStartupResult;import com.amazonaws.mobileconnectors.apigateway.ApiClientFactory;import com.amazonaws.mobileconnectors.apigateway.ApiRequest;import com.amazonaws.mobileconnectors.apigateway.ApiResponse;import com.amazonaws.util.IOUtils;import com.amazonaws.util.StringUtils;
import java.io.InputStream;import java.util.HashMap;import java.util.Map;
// TODO Replace this with your api friendly name and client class nameimport YOUR_API_RESOURCE_NAME.YOUR_APP_NAME_XXXXClient;
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName();
// TODO Replace this with your client class name private YOUR_APP_NAME_XXXXClient apiClient;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
// Initialize the AWS Mobile Client AWSMobileClient.getInstance().initialize(this, new AWSStartupHandler() { @Override public void onComplete(AWSStartupResult awsStartupResult) { Log.d(TAG, "AWSMobileClient is instantiated and you are connected to AWS!"); } }).execute();
// Create the client apiClient = new ApiClientFactory() .credentialsProvider(AWSMobileClient.getInstance()) .build(YOUR_API_CLIENT_NAME.class);
doInvokeAPI(); }
public void doInvokeAPI() { // Create components of api request final String method = "GET"; final String path = "/items";
final String body = ""; final byte[] content = body.getBytes(StringUtils.UTF8);
final Map parameters = new HashMap<>(); parameters.put("lang", "en_US");
final Map headers = new HashMap<>();
// Use components to create the api request ApiRequest localRequest = new ApiRequest(apiClient.getClass().getSimpleName()) .withPath(path) .withHttpMethod(HttpMethodName.valueOf(method)) .withHeaders(headers) .addHeader("Content-Type", "application/json") .withParameters(parameters);
// Only set body if it has content. if (body.length() > 0) { localRequest = localRequest .addHeader("Content-Length", String.valueOf(content.length)) .withBody(content); }
final ApiRequest request = localRequest;
// Make network call on background thread new Thread(new Runnable() { @Override public void run() { try { Log.d(TAG, "Invoking API w/ Request : " + request.getHttpMethod() + ":" + request.getPath());
final ApiResponse response = apiClient.execute(request);
final InputStream responseContentStream = response.getContent();
if (responseContentStream != null) { final String responseData = IOUtils.toString(responseContentStream); Log.d(TAG, "Response : " + responseData); }
Log.d(TAG, response.getStatusCode() + " " + response.getStatusText());
} catch (final Exception exception) { Log.e(TAG, exception.getMessage(), exception); exception.printStackTrace(); } } }).start(); }}
Cognito User Pools authorization
When invoking an API Gateway endpoint with Cognito User Pools authorizer, you can leverage the AWSMobileClient
to dynamically refresh and pass tokens to your endpoint. Using the example from the previous section, update the doInvokeAPI()
so that it takes a "token" string argument like doInvokeAPI(String token)
. Next, add a header for the token to be passed with .addHeader("Authorization", token)
and set the service configuration to have credentialsProvider(null)
. Finally, overload the doInvokeAPI()
with a new definition that gets the Cognito User Pools token from the AWSMobileClient
as below:
//Pass in null for credentialsProviderapiClient = new ApiClientFactory() .credentialsProvider(null) .build(YOUR_API_CLIENT_NAME.class);
//New overloaded function that gets Cognito User Pools tokenspublic void doInvokeAPI(){ AWSMobileClient.getInstance().getTokens(new Callback<Tokens>() { @Override public void onResult(Tokens tokens) { doInvokeAPI(tokens.getIdToken().getTokenString()); }
@Override public void onError(Exception e) { e.printStackTrace(); } });}
//Updated function with arguments and code updatespublic void doInvokeAPI(String token) { ApiRequest localRequest = new ApiRequest(apiClient.getClass().getSimpleName()) .withPath(path) .withHttpMethod(HttpMethodName.valueOf(method)) .withHeaders(headers) .addHeader("Content-Type", "application/json") .addHeader("Authorization", token) //Use JWT token .withParameters(parameters);}
You can then invoke this method with doInvokeAPI()
from your application code and it will pass the IdToken from Cognito User Pools as an Authorization
header.