diff --git a/docs/fragments/reactnative.md b/docs/fragments/reactnative.md index 15aa8ce0e69..204f3add398 100644 --- a/docs/fragments/reactnative.md +++ b/docs/fragments/reactnative.md @@ -1,3 +1,12 @@ ## What we'll build -This tutorial guides you through setting up a backend and integrating that backend with your React Native app. You will create a “Todo app” with a GraphQL API and to store and retrieve items in a cloud database. In addition, we'll demonstrate how to authenticate users, communicate with our API, and set up continuous deployment and hosting. \ No newline at end of file +This tutorial guides you through setting up a backend and integrating that backend with your React Native app. You will create a “Todo app” with a GraphQL API and to store and retrieve items in a cloud database. In addition, we'll demonstrate how to authenticate users, communicate with our API, and set up continuous deployment and hosting. + +## Pre-requisites + +The first thing you should do is initialize a new React Native application. There are two ways to do this: + +1. Expo CLI - Easier for new React Native developers +2. React Native CLI - If you are already familiar with mobile development, enables you to build native code into your project. + +This tutorial will cover both, so use what's best for you. \ No newline at end of file diff --git a/docs/start/getting-started/data-model.md b/docs/start/getting-started/data-model.md index 43256973c87..363630bcbdb 100644 --- a/docs/start/getting-started/data-model.md +++ b/docs/start/getting-started/data-model.md @@ -3,12 +3,10 @@ title: Connect API and database to app description: Data model description filterKey: integration --- -## Data model +## API -The next step is to model our backend data. The [GraphQL Transform library](/cli/graphql-transformer/directives) provides custom Amplify directives you can use in your schema that allow you to do things like define data models, set up authentication and authorization requirements for your data, and even configure serverless functions as resolvers. - - - + + diff --git a/docs/start/getting-started/fragments/react/api.md b/docs/start/getting-started/fragments/react/api.md new file mode 100644 index 00000000000..c4ab8216e5e --- /dev/null +++ b/docs/start/getting-started/fragments/react/api.md @@ -0,0 +1,218 @@ +Now that you’ve created and configured a React app and initialized a new Amplify project, you can add a feature. The first feature you will add is an API. + +The Amplify CLI supports creating and interacting with two types of API categories: REST and GraphQL. + +The API you will be creating in this step is a GraphQL API using AWS AppSync (a managed GraphQL service) and the database will be Amazon DynamoDB (a NoSQL database). + +## Create a GraphQL API and database + +To add the API, run the following command. + +```sh +amplify add api + +? Please select from one of the below mentioned services: GraphQL +? Provide API name: myapi +? Choose the default authorization type for the API: API Key +? Enter a description for the API key: demo +? After how many days from now the API key should expire: 7 (or your preferred expiration) +? Do you want to configure advanced settings for the GraphQL API: N +? Do you have an annotated GraphQL schema? N +? Do you want a guided schema creation? Y +? What best describes your project: Single object with fields +? Do you want to edit the schema now? Y +``` + +The CLI should open this schema in your text editor (__amplify/backend/api/myapi/schema.graphql +__). + +```graphql +type Todo @model { + id: ID! + name: String! + description: String +} +``` + +The schema generated is for a Todo app. You'll notice a directive on the `Todo` type of `@model`. This directive is part of the [GraphQL transform](/cli/graphql-transformer/directives) library of Amplify. + +The GraphQL Transform Library provides custom directives you can use in your schema that allow you to do things like define data models, set up authentication and authorization rules, configure serverless functions as resolvers, and more. + +A type decorated with the `@model` directive will scaffold out the database table for the type (Todo table), the schema for CRUD (create, read, update, delete) and list operations, and the GraphQL resolvers needed to make everything work together. + +From the command line, press __enter__ to accept the schema and continue to the next steps. + +### Test your API + +To test this out locally, you can run the `mock` command: + +```sh +amplify mock api + +# Before mocking you will be walked through the following steps for GraphQL code generation +? Choose the code generation language target: javascript (or preferred target) +? Enter the file name pattern of graphql queries, mutations and subscriptions: src/graphql/**/*.js +? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions: Yes +? Enter maximum statement depth [increase from default if your schema is deeply nested] 2 +``` + +This will open the GraphiQL explorer on a local port. From the test environment you can try out different operations locally, like queries and mutations, before deploying the backend. + +Try running a couple of mutations locally and then querying for the todos: + +```graphql +mutation createTodo { + createTodo(input: { + name: "Build an API" + description: "Build a serverless API with Amplify and GraphQL" + }) { + id + name + description + } +} + +query listTodos { + listTodos { + items { + id + description + name + } + } +} +``` + +### Deploying the API + +To deploy this backend, run the `push` command: + +```sh +amplify push + +? Are you sure you want to continue? Y + +# If you did not mock the API, you will be walked through the following questions for GraphQL code generation +? Do you want to generate code for your newly created GraphQL API? Y +? Choose the code generation language target: javascript +? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions? Y +? Enter maximum statement depth [increase from default if your schema is deeply nested]: 2 +``` + +Now the API and database have been deployed and you can start interacting with it. + +The API you have deployed is for a Todo app, including operations for creating, reading, updating, deleting, and listing todos. + +To view the GraphQL API in the AppSync console at any time, run the following command: + +```sh +amplify console api +``` + +To view your entire app in the Amplify console at any time, run the following command: + +```sh +amplify console +``` + +## Connect frontend to API + +For a user interface to interact with this API, you will create a way to list and create todos. To do this, you will create a form with a button to create todos and way to fetch and render a list of todos. + +Open __src/App.js__ and update it with the following code: + +```javascript +/* src/App.js */ +import React, { useEffect, useState } from 'react' +import { API, graphqlOperation } from 'aws-amplify' +import { createTodo } from './graphql/mutations' +import { listTodos } from './graphql/queries' + +const initialState = { name: '', description: '' } + +const App = () => { + const [formState, setFormState] = useState(initialState) + const [todos, setTodos] = useState([]) + + useEffect(() => { + fetchTodos() + }, []) + + function setInput(key, value) { + setFormState({ ...formState, [key]: value }) + } + + async function fetchTodos() { + try { + const todoData = await API.graphql(graphqlOperation(listTodos)) + const todos = todoData.data.listTodos.items + setTodos(todos) + } catch (err) { console.log('error fetching todos') } + } + + async function addTodo() { + try { + const todo = { ...formState } + setTodos([...todos, todo]) + setFormState(initialState) + await API.graphql(graphqlOperation(createTodo, {input: todo})) + } catch (err) { + console.log('error creating todo:', err) + } + } + + return ( +
+

Amplify Todos

+ setInput('name', event.target.value)} + style={styles.input} + value={formState.name} + placeholder="Name" + /> + setInput('description', event.target.value)} + style={styles.input} + value={formState.description} + placeholder="Description" + /> + + { + todos.map((todo, index) => ( +
+

{todo.name}

+

{todo.description}

+
+ )) + } +
+ ) +} + +const styles = { + container: { width: 400, margin: '0 auto', display: 'flex', flex: 1, flexDirection: 'column', justifyContent: 'center', padding: 20 }, + todo: { marginBottom: 15 }, + input: { border: 'none', backgroundColor: '#ddd', marginBottom: 10, padding: 8, fontSize: 18 }, + todoName: { fontSize: 20, fontWeight: 'bold' }, + todoDescription: { marginBottom: 0 }, + button: { backgroundColor: 'black', color: 'white', outline: 'none', fontSize: 18, padding: '12px 0px' } +} + +export default App +``` + +Let's walk through some of the functions: + +__useEffect__ - When the component loads, the `useEffect` hook is called and it invokes the `fetchTodos` function. + +__fetchTodos__ - Uses the Amplify `API` category to call the AppSync GraphQL API with the `listTodos` query. Once the data is returned, the items array is passed in to the `setTodos` function to update the local state. + +__createTodo__ - Uses the Amplify `API` category to call the AppSync GraphQL API with the `createTodo` mutation. A difference between the `listTodos` query and the `createTodo` mutation is that `createTodo` accepts an argument containing the variables needed for the mutation. + +## Run locally + +Next, run the app and you should see the form rendered to the screen and be able to create and view the list of todos: + +```sh +npm start +``` \ No newline at end of file diff --git a/docs/start/getting-started/fragments/react/auth.md b/docs/start/getting-started/fragments/react/auth.md index 254bbe0aa26..24f348833b3 100644 --- a/docs/start/getting-started/fragments/react/auth.md +++ b/docs/start/getting-started/fragments/react/auth.md @@ -1,79 +1,65 @@ -Now that our project is set up, the first thing we'll do is add authentication. This way we can keep track of which photos belong to which users, as well as make sure only people registered for the app can upload photos. +The next feature you will be adding is authentication. ## Authentication with Amplify The Amplify Framework uses [Amazon Cognito](https://aws.amazon.com/cognito/) as the main authentication provider. Amazon Cognito is a robust user directory service that handles user registration, authentication, account recovery & other operations. In this tutorial, you'll learn how to add authentication to your application using Amazon Cognito and username/password login. -## Create authentication backend +## Create authentication service -We'll use the Amplify CLI to add the `auth` category to our project. From the root of your project, run the following: - -```bash +```sh amplify add auth -``` - -The CLI will prompt you for more information, - -```bash -Do you want to use the default authentication and security configuration (default configuration) -How do you want users to be able to sign in (Username) - -Do you want to configure advanced settings (No, I am done) +? Do you want to use the default authentication and security configuration? Default configuration +? How do you want users to be able to sign in? Username +? Do you want to configure advanced settings? No, I am done. ``` -This will use the default settings in Cognito for username/password login. Now that we've defined our authentication needs it's time to deploy our Cognito user pool on AWS. To do that run: +To deploy the service, run the `push` command: -```bash +```sh amplify push -``` -The Amplify `push` command takes the templates generated by the Amplify CLI and pushes them to the cloud. Your AWS resources are then updated to match the new requirements. +? Are you sure you want to continue? Y +``` -Now, the authentication service has been deployed and you can start using it. To view the services deployed in your project at any time, run the following command: +Now, the authentication service has been deployed and you can start using it. To view the deployed services in your project at any time, go to Amplify Console by running the following command: ```sh -$ amplify console +amplify console ``` ## Create login UI -Now that we have our authentication backend deployed to AWS, it's time to add authentication to our React app. Creating the login flow can be quite difficult and time consuming to get right. Luckily Amplify Framework has an authentication UI component we can use that will provide the entire authentication flow for us, using our configuration specified in our `aws-exports.js` file. +Now that we have our authentication service deployed to AWS, it's time to add authentication to our React app. Creating the login flow can be quite difficult and time consuming to get right. Luckily Amplify Framework has an authentication UI component we can use that will provide the entire authentication flow for us, using our configuration specified in our __aws-exports.js__ file. + +Open __src/App.js__ and make the following changes: -In your editor, open up `src/App.js` and replace it with the following: +1. Import the `withAuthenticator` component: ```javascript -import React from "react"; -import "./App.css"; -import { withAuthenticator } from "aws-amplify-react"; - -function App() { - return ( -
-
-

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- ); -} - -export default withAuthenticator(App, true); +import { withAuthenticator } from 'aws-amplify-react' ``` -Run `npm start` to launch `localhost` to see the authentication UI below: +2. Change the default export to be the `withAuthenticator` wrapping the main component: + +```javascript +export default withAuthenticator(App) +``` + +Run the app to see the new Authentication flow protecting the app: + +```sh +npm start +``` + +Now you should see the app load with an authentication flow allowing users to sign up and sign in. + +In this example, you used the React Native UI library and the `withAuthenticator` to quickly get up and running with a real-world authentication flow. + +You can also customize this component to add or remove fields, update styling, or other configurations. To configure this component, check out the documentation [here](). -![login screen](https://raw.githubusercontent.com/aws-samples/create-react-app-auth-amplify/master/src/images/auth.gif) +In addition to the `withAuthenticator` you can build custom authentication flows using the `Auth` class. -Now that we have login support, go ahead and create a user. Once you successfully login, you should see the React boilerplate along with a new header and logout button. The header is part of the authentication component and can be customized or removed. We'll leave it here so we can focus on the photo sharing functionality. +`Auth` has over 30 methods including `signUp`, `signIn`, `forgotPasword`, and `signOut` that allow you full control over all aspects of the user authentication flow. Check out the complete API [here](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html) -In the next step, we'll set our data model and API so that we can upload and display photos. +In the next section, you'll host your app on the Amplify Console, a hosting service complete with a globally available CDN, atomic deployments, easy custom domains, and CI / CD. \ No newline at end of file diff --git a/docs/start/getting-started/fragments/react/data-model.md b/docs/start/getting-started/fragments/react/data-model.md deleted file mode 100644 index d9fa798bdfd..00000000000 --- a/docs/start/getting-started/fragments/react/data-model.md +++ /dev/null @@ -1,162 +0,0 @@ -### Data requirements - -For this app, we have the following requirements: - -1. A photo album screen that shows a list of photos -2. Ability to view details on a particular photo -3. Ability to store data about uploaded photos - -### Model the data with the GraphQL Transform - -Given these requirements, we'll need to be able to display a list of photos and upload photos, meaning there will definitely be a Photo entity in the app. In GraphQL we would use a `type` to define that entity, like so: - -```graphql -type Photo { - id: ID! - url: String! - description: String! -} -``` - -Because we're using Amplify, we can use the GraphQL Schema Definition Language (SDL) and custom Amplify directives to define our backend requirements for our API. The GraphQL Transform library then converts your SDL definition into a set of fully descriptive AWS CloudFormation templates that implement your data model. - -Since we know we need to store data about the uploaded photos, we first need to define our `Photo` type as a model: - -```graphql -type Photo @model { - id: ID! - url: String! - description: String! -} -``` - -The `@model` directive let's Amplify know we intend for this type to have data that needs to be stored. This will create a DynamoDB table for us and make all GraphQL operations available in the API. - -Next, we need to set up some authorization rules around the photos. Only the uploader should be able to remove a photo, but everyone should be able to view them. We can use the `@auth` directive to set up our authorization strategy: - -```graphql -type Photo - @model(subscriptions: { level: public }) - @auth(rules: [{ allow: owner, queries: null }]) { - id: ID! - url: String! - description: String! -} -``` - -We also updated the `@model` directive to specify we wanted subscriptions for photos to be available to everyone, this way, when photos are added or removed by other users, we can get those udpates in realtime in our app. When we create the API we'll use this type definition in our schema. - -## Create GraphQL API and database - -Now that the data is modeled, it's time to create the GraphQL API. From the root of the project, runthe following: - -```bash -$ amplify add api -``` - -You'll be prompted for some information so that Amplify can create the right infrastructure to support your API. For each question, choose the options listed below: - -```bash -# Amplify supports both REST and GraphQL APIs -Please select from one of the below mentioned services (GraphQL) - -Provide API name (photoshare) - -# Because we have user specific behavior in our app we need to authenticate users -Choose an authorization type for the API (Cognito User Pool) - -# Because we use a schema to create the backend you can share these schemas and use them as boilerplates -Do you have an annotated GraphQL schema (No) - -# Since we don't have a schema we want a guided creation -Do you want a guided schema creation (Yes) - -# We only have one data type so we don't need to handle any data relationships -What best describes your project (Single object with fields (e.g., “Todo” with ID, name, description)) - -# This option will open a `schema.graphql` file in our editor -# Replace the TODO example type with the Photo type from above -# Save the file and then come back to the terminal -Do you want to edit the schema now (Yes) - -# Once you have updated the schema.graphql file and saved it, press enter -Press enter to continue -``` - -Now that the API has been successfully created. We need to push our updated configuration to the cloud so our API can be deployed: - -```bash -amplify push -``` - -When you run `amplify push`, you'll have the option to have all the GraphQL operations found in your schema generated for you. Choose the following options: - -```bash -Do you want to generate code for your newly created GraphQL API (Yes) - -Choose the code generation language target (javascript) - -Enter the file name pattern of graphql queries, mutations and subscriptions (src/graphql/**/*.js) - -Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions (Yes) - -Enter maximum statement depth [increase from default if your schema is deeply nested] (2) -``` - -## Connect frontend to API - -We don't have any photos uploaded yet, but we're going to set up the query for listing the photos so we can see them once we can upload. - -Open up `src/App.js` and modify it with the following: - -```javascript - import React, { useState, useEffect } from "react"; - import "./App.css"; - import { withAuthenticator } from "aws-amplify-react"; - import { API, graphqlOperation } from 'aws-amplify' - - import { listPhotos } from './graphql/queries' - - function App() { - const [photos, setPhotos] = useState([]) - - useEffect(() => { - const fetchPhotos = async () => { - const data = await API.graphql(graphqlOperation(listPhotos)) - setPhotos(data.listPhotos.items) - } - - fetchPhotos() - }, [setPhotos]) - - return ( -
-
-

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- {!photos.length &&

No photos yet.

} - {photos.map(photo => ( -
- {photo.description} -
- ))} -
-
- ); - } - - export default withAuthenticator(App, true); -``` - -Because we don't have any photos stored, at this point you should see "No photos yet" when you run the app. In the next step we'll set up storage for our photos and handle uploads! diff --git a/docs/start/getting-started/fragments/react/setup.md b/docs/start/getting-started/fragments/react/setup.md index 3effa4a1dc8..2eebbed1d31 100644 --- a/docs/start/getting-started/fragments/react/setup.md +++ b/docs/start/getting-started/fragments/react/setup.md @@ -4,11 +4,11 @@ To set up the project, we'll first create a new React app with [create-react-app](https://reactjs.org/docs/create-a-new-react-app.html), a CLI tool used to bootstrap a React app using current best practices. We'll then add Amplify and initialize a new project. From your projects directory, run the following commands: ```bash -npx create-react-app photo-share -cd photo-share +npx create-react-app react-amplified +cd react-amplified ``` -This creates a new React app in a directory called `photo-share` and then switches us into that new directory. Now that we're in the root of the project, we can run the app by using the following command: +This creates a new React app in a directory called `react-amplified` and then switches us into that new directory. Now that we're in the root of the project, we can run the app by using the following command: ```bash npm start @@ -27,7 +27,7 @@ amplify init When you initialize Amplify you'll be prompted for some information about the app: ```bash -Enter a name for the project (photo-share) +Enter a name for the project (react-amplified) # All AWS services you provision for your app are grouped into an "environment" # A common naming convention is dev, staging, and production @@ -37,7 +37,7 @@ Enter a name for the environment (dev) Choose your default editor # Amplify supports JavaScript (Web & React Native), iOS, and Android apps -Choose the type of app that you're building (javascript) +Choose the type of app that youre building (javascript) What JavaScript framework are you using (react) @@ -53,11 +53,11 @@ Start command (npm start) Do you want to use an AWS profile ``` -> Where possible the CLI will infer the proper configuration based on the type of project Amplify is being initialzed in. In this case it knew we are using CRA and provided the proper configuration for type of app, framework, source, distribution, build, and start options. +> Where possible the CLI will infer the proper configuration based on the type of project Amplify is being initialized in. In this case it knew we are using Create React App and provided the proper configuration for type of app, framework, source, distribution, build, and start options. When you initialize a new Amplify project, a few things happen: -- It creates a top level directory called `amplify` that stores your backend definition. During the tutorial you'll add capabilities such as authentication, GraphQL API, storage, and set up authorization rules for the API. As you add features, the `amplify` folder will grow with infrastructure-as-code templates that define your backend stack. Infrastructure-as-code is a best practice way to create a replicable backend stack. +- It creates a top level directory called `amplify` that stores your backend definition. During the tutorial you'll add capabilities such as a GraphQL API and authentication. As you add features, the `amplify` folder will grow with infrastructure-as-code templates that define your backend stack. Infrastructure-as-code is a best practice way to create a replicable backend stack. - It creates a file called `aws-exports.js` in the `src` directory that holds all the configuration for the services you create with Amplify. This is how the Amplify client is able to get the necessary information about your backend services. - It modifies the `.gitignore` file, adding some generated files to the ignore list - A cloud project is created for you in the AWS Amplify Console that can be accessed by running `amplify console`. The Console provides a list of backend environments, deep links to provisioned resources per Amplify category, status of recent deployments, and instructions on how to promote, clone, pull, and delete backend resources @@ -74,46 +74,17 @@ The `aws-amplify` package is the main library for working with Amplify in your a ## Set up frontend -Next, we need to configure Amplify so that we can use the lib to interact with our backend services. Open up `src/index.js` and add replace it with the following: +Next, we need to configure Amplify so that we can use the lib to interact with our backend services. Open up __src/index.js__ and add the following code below the last import: ```javascript -import React from "react"; -import ReactDOM from "react-dom"; import Amplify from "aws-amplify"; -import "./index.css"; -import App from "./App"; -import * as serviceWorker from "./serviceWorker"; import awsExports from "./aws-exports"; - Amplify.configure(awsExports); - -ReactDOM.render(, document.getElementById("root")); - -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister(); ``` -And that's all it takes to configure Amplify. As you add or remove categories and make updates to your backend configuration, the configuration in `aws-exports.js` will update automatically. - -### Clean Up boilerplate - -First we'll remove some files we won't be using so we can focus on the parts of the app we'll want to update. To clean up the project a bit, remove the following files: - -- `src/App.test.js` -- `src/setupTests.js` -- `src/logo.svg` +And that's all it takes to configure Amplify. As you add or remove categories and make updates to your backend configuration using the Amplify CLI, the configuration in __aws-exports.js__ will update automatically. -Next, in `src/App.js` remove the import for `logo.svg` and the `img` tag in the header. - -```javascript -import logo from './logo.svg' -... -logo -``` - -After removing the image, run the following command: +Next, run the following command: ```bash amplify status @@ -126,7 +97,6 @@ Current Environment: dev | Category | Resource name | Operation | Provider plugin | | -------- | ------------- | --------- | --------------- | - ``` -Now that our React app is set up and Amplify is initialized, we're ready to add authentication in the next step. \ No newline at end of file +Now that our React app is set up and Amplify is initialized, we're ready to add an API in the next step. \ No newline at end of file diff --git a/docs/start/getting-started/fragments/react/storage.md b/docs/start/getting-started/fragments/react/storage.md deleted file mode 100644 index 62e16d00ff2..00000000000 --- a/docs/start/getting-started/fragments/react/storage.md +++ /dev/null @@ -1,220 +0,0 @@ -## Add storage to your backend - -``` -amplify add storage -? Who should have access: Auth and guest users - - -? What kind of access do you want for Authenticated users? -◉ create/update -◉ read -◉ delete - - -? What kind of access do you want for Guest users? -◯ create/update -◉ read -◯ delete - - -? Do you want to add a Lambda Trigger for your S3 Bucket? No -``` - -## Update your data model - -```js:amplify/backend/api/photoalbums/schema.graphql - -type Album @model @auth(rules: [{allow: owner}]) { - id: ID! - name: String! - photos: [Photo] @connection(name: "AlbumPhotos") -} - -type Photo @model @auth(rules: [{allow: owner}]) { - id: ID! - album: Album @connection(name: "AlbumPhotos") - bucket: String! - fullsize: PhotoS3Info! - thumbnail: PhotoS3Info! -} - -type PhotoS3Info { - key: String! - width: Int! - height: Int! -} -``` - -``` -amplify push -``` - -## Add Photo Uploads - -In order to handle file uploads, we'll need to allow the user to pick a photo, and upload it to S3. We'll then take the key given back to us from S3 and store it in our GraphQL API for use in the app. - -Open up `src/App.js` and update with the folowing: - -```javascript - import React, { useState, useEffect } from "react"; - import "./App.css"; - import { withAuthenticator, S3Image } from "aws-amplify-react"; - import { API, Storage, graphqlOperation } from "aws-amplify"; - import uuid from "uuid/v4"; - - import { listPhotos } from "./graphql/queries"; - import { createPhoto, deletePhoto } from "./graphql/mutations"; - - function App() { - const [photos, setPhotos] = useState([]); - const [file, setFile] = useState(); - - useEffect(() => { - const fetchPhotos = async () => { - const result = await API.graphql(graphqlOperation(listPhotos)); - setPhotos(result.data.listPhotos.items); - }; - - fetchPhotos(); - }, [setPhotos]); - - const onFileSelected = e => { - setFile(e.target.files[0]); - }; - - const uploadPhoto = async () => { - const result = await Storage.put(`${uuid()}/${file.name}`, file); - await API.graphql( - graphqlOperation(createPhoto, { - input: { url: result.key } - }) - ); - }; - - const createDeletePhotoHandler = photo => { - return async () => { - if (global.confirm("Are you sure?")) { - Storage.remove(photo.url); - API.graphql(graphqlOperation(deletePhoto, { input: { id: photo.id } })); - } - }; - }; - - return ( -
-
- (e.target.value = null)} - onChange={onFileSelected} - /> - -
-
- {!photos.length &&

No photos yet.

} - {photos.map(photo => ( -
- - -
- ))} -
-
- ); - } - - export default withAuthenticator(App, true); -``` - -We'll also need to install the `uuid` package we use to create unique names for the photos: - -```bash -npm install uuid -``` - -Now let's update the styling just a bit, open `src/App.js` and add the following: - -```js - .App { - text-align: center; - } - - .App-logo { - height: 40vmin; - pointer-events: none; - } - - @media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } - } - - .App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; - } - - .App-link { - color: #61dafb; - } - - @keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } - } - - .Photo-gallery { - display: flex; - } - - .Photo-container { - width: 250px; - height: 250px; - margin: 8px; -+ position: relative; - } - - .Photo-container div { - width: 100%; - height: 100%; - } - - .Photo-container button { - position: absolute; - top: 8px; - right: 8px; - padding: 8px; - background-color: black; - color: white; - font-weight: bold; - cursor: pointer; - z-index: 2; - } - - .Photo { - width: 100%; - height: 100%; - object-fit: cover; - } - - .Photo-upload { - margin-top: 16px; - } -``` - -If you upload a new photo, you should see it update immediately in the gallery, you can also remove photos as well with the button at the top right. If you want to test how it behaves with multiple users, open another browser tab, create a second user, and upload some photos. They should appear in the first tab as well. - -Now that we have a fully functioning app, in the next step we'll deploy the application to the web! \ No newline at end of file diff --git a/docs/start/getting-started/fragments/reactnative/data-model.md b/docs/start/getting-started/fragments/reactnative/api.md similarity index 64% rename from docs/start/getting-started/fragments/reactnative/data-model.md rename to docs/start/getting-started/fragments/reactnative/api.md index 9a1e7a03524..3e227e117f4 100644 --- a/docs/start/getting-started/fragments/reactnative/data-model.md +++ b/docs/start/getting-started/fragments/reactnative/api.md @@ -1,3 +1,5 @@ +Now that you’ve created and configured a React Native app and initialized a new Amplify project, you can add a feature. The first feature you will add is an API. + The Amplify CLI supports creating and interacting with two types of API categories: REST and GraphQL. The API you will be creating in this step is a GraphQL API using AWS AppSync (a managed GraphQL service) and the database will be Amazon DynamoDB (a NoSQL database). @@ -7,7 +9,7 @@ The API you will be creating in this step is a GraphQL API using AWS AppSync (a To add the API, run the following command. ```sh -$ amplify add api +amplify add api ? Please select from one of the below mentioned services: GraphQL ? Provide API name: myapi @@ -21,10 +23,9 @@ $ amplify add api ? Do you want to edit the schema now? Y ``` -The CLI should open this schema in your text editor. +The CLI should open this schema in your text editor (__amplify/backend/api/myapi/schema.graphql__). ```graphql -# amplify/backend/api/myapi/schema.graphql type Todo @model { id: ID! name: String! @@ -32,28 +33,65 @@ type Todo @model { } ``` -The schema generated is for a Todo app. You'll notice a directive on the `Todo` type of `@model`. This directive is part of the GraphQL transform library of Amplify. +The schema generated is for a Todo app. You'll notice a directive on the `Todo` type of `@model`. This directive is part of the [GraphQL transform](/cli/graphql-transformer/directives) library of Amplify. + +The GraphQL Transform Library provides custom directives you can use in your schema that allow you to do things like define data models, set up authentication and authorization rules, configure serverless functions as resolvers, and more. -A type decorated with this directive will scaffold out the database table for the type (Todo table), the schema for CRUD (create, read, update, delete) and list operations, and the GraphQL resolvers needed to make everything work together. +A type decorated with the `@model` directive will scaffold out the database table for the type (Todo table), the schema for CRUD (create, read, update, delete) and list operations, and the GraphQL resolvers needed to make everything work together. + +From the command line, press __enter__ to accept the schema and continue to the next steps. ### Test your API To test this out locally, you can run the `mock` command: ```sh -$ amplify mock api +amplify mock api + +# Before mocking you will be walked through the following steps for GraphQL code generation +? Choose the code generation language target: javascript (or preferred target) +? Enter the file name pattern of graphql queries, mutations and subscriptions: src/graphql/**/*.js +? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions: Yes +? Enter maximum statement depth [increase from default if your schema is deeply nested] 2 ``` This will open the GraphiQL explorer on a local port. From the test environment you can try out different operations locally, like queries and mutations, before deploying the backend. -### Code generation +Try running a couple of mutations locally and then querying for the todos: + +```graphql +mutation createTodo { + createTodo(input: { + name: "Build an API" + description: "Build a serverless API with Amplify and GraphQL" + }) { + id + name + description + } +} + +query listTodos { + listTodos { + items { + id + description + name + } + } +} +``` + +### Deploying the API To deploy this backend, run the `push` command: ```sh -$ amplify push +amplify push ? Are you sure you want to continue? Y + +# If you did not mock the API, you will be walked through the following questions for GraphQL code generation ? Do you want to generate code for your newly created GraphQL API? Y ? Choose the code generation language target: javascript ? Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions? Y @@ -64,11 +102,23 @@ Now the API and database have been deployed and you can start interacting with i The API you have deployed is for a Todo app, including operations for creating, reading, updating, deleting, and listing todos. +To view the GraphQL API in the AppSync console at any time, run the following command: + +```sh +amplify console api +``` + +To view your entire app in the Amplify console at any time, run the following command: + +```sh +amplify console +``` + ## Connect frontend to API For a user interface to interact with this API, you will create a way to list and create todos. To do this, you will create a form with a button to create todos and way to fetch and render a list of todos. -Open App.js and update it with the following code (If you are using Expo, you also need to be sure to include the `Amplify.configure` configuration as well): +Open __App.js__ and update it with the following code (If you are using Expo, you also need to be sure to include the `Amplify.configure` configuration as well): ```javascript import React, { useEffect, useState } from 'react' @@ -156,16 +206,20 @@ __useEffect__ - When the component loads, the `useEffect` hook is called and it __fetchTodos__ - Uses the Amplify `API` category to call the AppSync GraphQL API with the `listTodos` query. Once the data is returned, the items array is passed in to the `setTodos` function to update the local state. -__createTodo__ - Uses the Amplify API category to call the AppSync GraphQL API with the `createTodo` mutation. A difference between the `listTodos` query and the `createTodo` mutation is that `createTodo` accepts an argument containing the variables needed for the mutation. +__createTodo__ - Uses the Amplify `API` category to call the AppSync GraphQL API with the `createTodo` mutation. A difference between the `listTodos` query and the `createTodo` mutation is that `createTodo` accepts an argument containing the variables needed for the mutation. ## Run locally Next, run the app and you should see the form rendered to the screen and be able to create and view the list of todos: ```sh -$ expo start +expo start + +# or + +npx react-native run-ios # or -$ npx react-native run-ios +npx react-native run-android ``` \ No newline at end of file diff --git a/docs/start/getting-started/fragments/reactnative/auth.md b/docs/start/getting-started/fragments/reactnative/auth.md index 9632913f61b..e93d5bc7432 100644 --- a/docs/start/getting-started/fragments/reactnative/auth.md +++ b/docs/start/getting-started/fragments/reactnative/auth.md @@ -1,13 +1,13 @@ -Now that you've created and configured a React Native project and initialized a new React Native app, you can add a feature. The first feature you will add is authentication. +The next feature you will be adding is authentication. ## Authentication with Amplify The Amplify Framework uses [Amazon Cognito](https://aws.amazon.com/cognito/) as the main authentication provider. Amazon Cognito is a robust user directory service that handles user registration, authentication, account recovery & other operations. In this tutorial, you'll learn how to add authentication to your application using Amazon Cognito and username/password login. -## Create authentication backend +## Create authentication service ```sh -$ amplify add auth +amplify add auth ? Do you want to use the default authentication and security configuration? Default configuration ? How do you want users to be able to sign in? Username @@ -17,7 +17,7 @@ $ amplify add auth To deploy the service, run the `push` command: ```sh -$ amplify push +amplify push ? Are you sure you want to continue? Y ``` @@ -25,12 +25,12 @@ $ amplify push Now, the authentication service has been deployed and you can start using it. To view the deployed services in your project at any time, go to Amplify Console by running the following command: ```sh -$ amplify console +amplify console ``` ## Create login UI -Now that we have our authentication service deployed to AWS, it's time to add authentication to our React app. Creating the login flow can be quite difficult and time consuming to get right. Luckily Amplify Framework has an authentication UI component we can use that will provide the entire authentication flow for us, using our configuration specified in our `aws-exports.js` file. +Now that we have our authentication service deployed to AWS, it's time to add authentication to our React app. Creating the login flow can be quite difficult and time consuming to get right. Luckily Amplify Framework has an authentication UI component we can use that will provide the entire authentication flow for us, using our configuration specified in our __aws-exports.js__ file. Open __App.js__ and make the following changes: @@ -51,13 +51,17 @@ Run the app to see the new Authentication flow protecting the app: ### With Expo ```sh -$ expo start +expo start ``` ### With the React Native CLI ```sh -$ npx react-native run-ios +npx react-native run-ios + +# or + +npx react-native run-android ``` Now you should see the app load with an authentication flow allowing users to sign up and sign in. @@ -68,6 +72,4 @@ You can also customize this component to add or remove fields, update styling, o In addition to the `withAuthenticator` you can build custom authentication flows using the `Auth` class. -`Auth` has over 30 methods including `signUp`, `signIn`, `forgotPasword`, and `signOut` that allow you full control over all aspects of the user authentication flow. Check out the complete API [here](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html) - -In the next section, you'll add an API and NoSQL database using Amazon DynamoDB and AWS AppSync. \ No newline at end of file +`Auth` has over 30 methods including `signUp`, `signIn`, `forgotPasword`, and `signOut` that allow you full control over all aspects of the user authentication flow. Check out the complete API [here](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html) \ No newline at end of file diff --git a/docs/start/getting-started/fragments/reactnative/setup.md b/docs/start/getting-started/fragments/reactnative/setup.md index d411ca425fb..2863b6ac50b 100644 --- a/docs/start/getting-started/fragments/reactnative/setup.md +++ b/docs/start/getting-started/fragments/reactnative/setup.md @@ -6,14 +6,14 @@ To get started, initialize a new React Native project. ### Using Expo ```sh -$ npm install -g expo-cli -$ expo init RNAmplify +npm install -g expo-cli +expo init RNAmplify ``` ### Using the React Native CLI ```sh -$ npx react-native init RNAmplify +npx react-native init RNAmplify ``` ## Initialize a new backend @@ -21,13 +21,13 @@ $ npx react-native init RNAmplify You are now ready to initialize a new Amplify project. To do so, change into the project directory ```sh -$ cd RNAmplify +cd RNAmplify ``` -and use the Amplify CLI: +and use the Amplify CLI to create the project: ```sh -$ amplify init +amplify init ? Enter a name for the project: rnamplify ? Enter a name for the environment: demo @@ -42,12 +42,14 @@ $ amplify init ? Please choose the profile you want to use: ``` -Once the amplify project has been initialized, you should see the following artifacts in your project: +When you initialize a new Amplify project, a few things happen: -1. __src/aws-exports.js__ - This file will hold the key value pairs of the resource information for the services created by the CLI. -2. __amplify__ directory - This will hold any back end code you will write for things like GraphQL schemas and serverless functions managed by the AWS services we'll be using. +- It creates a top level directory called `amplify` that stores your backend definition. During the tutorial you'll add capabilities such as a GraphQL API and authentication. As you add features, the `amplify` folder will grow with infrastructure-as-code templates that define your backend stack. Infrastructure-as-code is a best practice way to create a replicable backend stack. +- It creates a file called `aws-exports.js` in the `src` directory that holds all the configuration for the services you create with Amplify. This is how the Amplify client is able to get the necessary information about your backend services. +- It modifies the `.gitignore` file, adding some generated files to the ignore list. +- A cloud project is created for you in the AWS Amplify Console that can be accessed by running `amplify console`. The Console provides a list of backend environments, deep links to provisioned resources per Amplify category, status of recent deployments, and instructions on how to promote, clone, pull, and delete backend resources. -## Install Amplify dependencies +## Install Amplify libraries Next, install the local Amplify dependencies. The directions here will depend on whether you are using Expo or the React Native CLI. @@ -56,34 +58,34 @@ Next, install the local Amplify dependencies. The directions here will depend on With Expo, you only have to install the dependencies and then move on to the next step. ```sh -$ npm install aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo +npm install aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo # or -$ yarn add aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo +yarn add aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo ``` ### React Native ```sh -$ npm install aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo +npm install aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo # or -$ yarn add aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo +yarn add aws-amplify aws-amplify-react-native amazon-cognito-identity-js react-native-vector-icons @react-native-community/netinfo ``` You will next need to change into the the ios directory and install the pod dependencies: ```sh -$ cd ios -$ pod install -$ cd ../ +cd ios +pod install +cd ../ ``` Now open __ios/RNAmpIntr/Info.plist__ and add the following properties: -``` +```xml UIAppFonts AntDesign.ttf @@ -112,7 +114,7 @@ apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" ## Set up frontend -Finally, open __App.js__ (Expo) or __index.js__(React Native CLI) and add the following lines of code at the top of the file below the last import: +Finally, open __App.js__ (Expo) or __index.js__ (React Native CLI) and add the following lines of code at the top of the file below the last import: ```javascript import Amplify from 'aws-amplify' diff --git a/docs/start/getting-started/fragments/reactnative/storage.md b/docs/start/getting-started/fragments/reactnative/storage.md deleted file mode 100644 index 9fa10c8465c..00000000000 --- a/docs/start/getting-started/fragments/reactnative/storage.md +++ /dev/null @@ -1,243 +0,0 @@ -> To enable Storage, you must first enable authentication if you have not already by running `amplify add auth` from the command line. - -The Amplify CLI supports creating and interacting with two types of Storage categories: Files (Amazon S3) and Database (Amazon DynamoDB). - -The Storage example you will be creating in this step is an image upload and viewing app using Amazon S3. - -## Displaying an image picker - -In order to retrieve images from the camera roll, you'll need to install an image picker UI component. - -### With Expo -Install [Expo ImagePicker](https://docs.expo.io/versions/latest/sdk/imagepicker/) by running the following command. - -```sh -$ npm install expo-image-picker - -# or - -$ yarn add expo-image-picker -``` - -### With React Native CLI -Install and configure the [React Native Image Picker native module](https://github.com/react-native-community/react-native-image-picker) by running the following commands. - - -```sh -$ npm install react-native-image-picker - -$ cd ios && pod install && cd .. -``` - -You will also need to add `UsageDescription` on iOS and some permissions on Android, refer to the Install doc. - -## Add Storage to the backend - -To add Storage, run the following command. - -```sh -$ amplify add storage - -? Please select from one of the below mentioned services: Content -? Please provide a friendly name for your resource that will be used to label this category in the project: -? Please provide bucket name: -? Who should have access: Auth and guest users -? What kind of access do you want for Authenticated users? create, read, update, delete -? What kind of access do you want for Guest users? create, read, update, delete -? Do you want to add a Lambda Trigger for your S3 Bucket? N -``` - -Deploy the service by running the following command: - -```sh -$ amplify push -``` - -To view the Amazon S3 bucket at any time, you can open the Amplify console and click on __File storage__: - -```sh -$ amplify console -``` - -From the React Native application, you can use the Amplify `Storage` category to interact with the Amazon S3 bucket. - -In this example, you will use `Storage.put` to upload an image to the S3 bucket. - -This example will differ depending on whether you are using Expo or the React Native CLI. - -## Uploading an image with a project created using with Expo - -```javascript -import React, { useState, useEffect} from 'react'; -import { Button, Image, View } from 'react-native'; -import * as ImagePicker from 'expo-image-picker'; -import Constants from 'expo-constants'; -import * as Permissions from 'expo-permissions'; -import { Storage } from 'aws-amplify' - -import Amplify from 'aws-amplify' -import config from './aws-exports' -Amplify.configure(config) - -function App() { - useEffect(() => { - getPermissionAsync(); - }, []) - - async function getPermissionAsync() { - if (Constants.platform.ios) { - const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL); - if (status !== 'granted') { - alert('Sorry, we need camera roll permissions to make this work!'); - } - } - } - - async function getImageFromCameraRoll() { - let result = await ImagePicker.launchImageLibraryAsync({ - mediaTypes: ImagePicker.MediaTypeOptions.All, - allowsEditing: true, - aspect: [4, 3], - quality: 1 - }); - - if (!result.cancelled) { - const fileName = result.uri.split('/')[result.uri.split('/').length - 1] - uploadToStorage(result.uri, fileName) - } - }; - - async function uploadToStorage (pathToImageFile, fileName) { - try { - const response = await fetch(pathToImageFile) - const blob = await response.blob() - await Storage.put(fileName, blob) - console.log('image successfully stored!') - } catch (err) { - console.log('error storing image:', err) - } - } - - return ( - -