Next.js是我最喜欢的网络开发工具之一,但它是一个前端框架。你怎么能用它来构建一个全栈式的应用程序呢?在本教程中,我们将建立一个服务器端的Rendered Next.js应用程序,它有一个数据库支持的后端、静态图像存储和认证。它将以国家公园为主题--已登录的用户可以创建新的公园,所有人都可以查看所有已添加的公园。
如果你是Next.js的新手,我写了一个关于如何开始使用它的教程。如果你是AWS Amplify的新手,这里也有一个关于这个的教程。
创建你的应用后端
首先,创建一个新的Next应用程序:
npx create-next-app national-parks
确保你已经安装了Amplify CLI,如果没有,请按照以下说明操作
然后,为你的项目初始化Amplify。你应该能够接受它为你生成的配置,然后选择你的AWS配置文件或输入你的访问密钥。
amplify init
然后,我们将配置所需的服务。首先,我们将添加认证。
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
Do you want to configure advanced settings? No, I am done.
现在我们将为我们的应用程序添加存储。除了谁应该有访问权之外,所有问题都选择默认的配置选项--在这里,让认证的用户访问所有的操作,让未认证的用户有能力读取数据。
amplify add storage
? Please select from one of the below mentioned services: Content (Images, audio, video, etc.)
? Please provide a friendly name for your resource that will be used to label this category in the project: s37cd140d1
? Please provide bucket name: nationalparkbrowser248f6fd94d4f46f99a951df475e8
? 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? read
? Do you want to add a Lambda Trigger for your S3 Bucket? No
最后,我们将创建一个API。我们将选择GraphQL并使用API密钥进行授权。在你的文本编辑器中打开GraphQL模式。
amplify add api
? Please select from one of the below mentioned services: GraphQL
? Provide API name: nationalparks
? Choose the default authorization type for the API API key
? Enter a description for the API key:
? After how many days from now the API key should expire (1-365): 7
? Do you want to configure advanced settings for the GraphQL API No, I am done.
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
如果你的schema.graphql文件没有在你的文本编辑器中打开,就把它打开。它将在amplify/backend/api/nationalparks 下。那里将有一个GraphQL模式的样本,但我们将编辑它以获得我们需要的数据格式。
我们将创建两个模型。S3Object和Park。Park 将存储我们的公园--每个公园将有一个id、一个名字和一个图像。该图像将引用存储在Amazon S3中的图像(我们在运行amplify add storage 时创建了一个桶)。S3Object 将有关于存储在S3上的图像的信息--它的桶、区域和密钥。我们将使用密钥来访问我们应用程序中的图像。
type S3Object {
bucket: String!
region: String!
key: String!
}
type Park @model {
id: ID!
name: String!
image: S3Object
}
现在运行amplify push ,将你的资源部署到云中!你现在有了一个完全部署的后端。
安装Amplify库。这些将允许我们使用JavaScript辅助代码和React组件来加速我们的前端开发。
npm i aws-amplify @aws-amplify/ui-react
一旦我们的后端部署完毕,我们将需要使用Amplify.configure() 将我们的前端与后端连接起来。我们将使用Amplify自动生成的src/aws-exports.js 文件中的配置信息,同时确保将ssr 标志设置为true ,这样我们就可以从服务器上的API中提取。
把这个添加到你的pages/_app.js 的顶部。
import Amplify from 'aws-amplify'
import config from '../src/aws-exports'
Amplify.configure({ ...config, ssr: true })
前端逻辑
吁!配置代码完成了。完成了配置代码,现在我们可以编写我们的前端React逻辑了。让我们首先创建一个表单,以便创建一个新的公园。创建一个文件pages/create-park.js ,该文件将放置一个页面,用来渲染我们的表单。在该文件中创建一个React组件。
// create-park.js
function CreatePark () {
return <h1>Create Park</h1>
}
export default CreatePark
然后,我们将使用withAuthenticator 高阶组件,要求在进入/create-park 页面前进行签到。它还将启用签到并要求账户确认。
// create-park.js
import { withAuthenticator } from '@aws-amplify/ui-react'
function CreatePark () {
return <h1>Create Park</h1>
}
export default withAuthenticator(CreatePark)
现在我们将创建一个React表单,用户可以在其中输入公园的名称和图片。
// create-park.js
import { useState } from 'react'
import { withAuthenticator } from '@aws-amplify/ui-react'
function CreatePark () {
const [name, setName] = useState('')
const [image, setImage] = useState('')
const handleSubmit = async () => {
}
return (
<form onSubmit={handleSubmit}>
<h2>Create a Park</h2>
<label htmlFor='name'>Name</label>
<input type='text' id='name' onChange={e => setName(e.target.value)} />
<label htmlFor='image'>Image</label>
<input type='file' id='image' onChange={e => setImage(e.target.files[0])} />
<input type='submit' value='create' />
</form>
)
}
export default withAuthenticator(CreatePark)
最后,我们将实现handleSubmit ,该功能将把用户的图片上传到S3,然后使用GraphQL API将我们新创建的公园存储到我们的数据库中。我们将再次从aws-exports.js 中导入配置信息和Amplify在src/graphql 目录中生成的GraphQL突变之一。
然后,我们将使用Storage.put() ,以图像的名称为键,以图像本身为值来上传图像。然后,我们将使用API.graphql ,用用户输入的数据和关于S3桶的配置信息来运行graphQL突变。
// create-park.js
import { useState } from 'react'
import { API, Storage } from 'aws-amplify'
import { withAuthenticator } from '@aws-amplify/ui-react'
import { createPark } from '../src/graphql/mutations'
import config from '../src/aws-exports'
function CreatePark () {
const [name, setName] = useState('')
const [image, setImage] = useState('')
const handleSubmit = async e => {
e.preventDefault()
// upload the image to S3
const uploadedImage = await Storage.put(image.name, image)
console.log(uploadedImage)
// submit the GraphQL query
const newPark = await API.graphql({
query: createPark,
variables: {
input: {
name,
image: {
// use the image's region and bucket (from aws-exports) as well as the key from the uploaded image
region: config.aws_user_files_s3_bucket_region,
bucket: config.aws_user_files_s3_bucket,
key: uploadedImage.key
}
}
}
})
console.log(newPark)
}
return (
<form onSubmit={handleSubmit}>
<h2>Create a Park</h2>
<label htmlFor='name'>Name</label>
<input type='text' id='name' onChange={e => setName(e.target.value)} />
<label htmlFor='image'>Image</label>
<input type='file' id='image' onChange={e => setImage(e.target.files[0])} />
<input type='submit' value='create' />
</form>
)
}
export default withAuthenticator(CreatePark)
如果你愿意,这里有几行CSS,你可以粘贴到styles/globals.css 文件中,使应用程序看起来更美观。
amplify-s3-image {
--width: 70%;
overflow: hidden;
margin: 0 auto;
}
.container {
max-width: 1000px;
margin: 0 auto;
padding: 0 2rem;
text-align: center;
}
.img-square img h2 {
margin: 0 auto;
text-align: center;
}
最后,我们将在索引页上列出所有的公园。我们将使用在src/graphql/queries.js 中生成的listParks graphql查询来获取公园,并使用AmplifyS3Image 组件来渲染页面上的图像。我们将在服务器端获取公园,这样当有新的公园加入时,我们的应用程序将动态地更新。
import Head from 'next/head'
import { withSSRContext } from 'aws-amplify'
import { listParks } from '../src/graphql/queries'
import { AmplifyS3Image } from '@aws-amplify/ui-react'
import Link from 'next/link'
export async function getServerSideProps () {
const SSR = withSSRContext()
const { data } = await SSR.API.graphql({ query: listParks })
return {
props: {
parks: data.listParks.items
}
}
}
export default function Home ({ parks }) {
return (
<div>
<Head>
<title>National Parks</title>
</Head>
<div className='container'>
<h1>National Parks <Link href='/create-park'>(+)</Link></h1>
<div className='img-grid'>
{parks.map(park => {
return (
<div key={park.id} className='img-square'>
<h2>{park.name}</h2>
{/* use the AmplifyS3Image component to render the park's image using its S3 key */}
<AmplifyS3Image imgKey={park.image.key} height='200px' />
</div>
)
})}
</div>
</div>
</div>
)
}
前端部署
现在我们的应用程序有了一个完整的前端让我们通过Amplify托管部署它。把你的代码推送到GitHub仓库,然后为你的应用程序打开Amplify控制台。点击frontend environments tab ,然后点击connect app 按钮。选择你的仓库,使用自动生成的配置,然后save and deploy 。这将需要几分钟的时间,然后你的应用程序就可以上线了
不需要额外的配置,Amplify会推断出你正在创建一个SSR Next.js应用程序,并为你的应用程序部署所需的主机资源。如果你有兴趣,这里有更多的信息!
清理
你可能不想继续部署应用程序,在这种情况下,你可以点击AWS控制台中的delete app 按钮或从命令行中运行amplify delete 。这将从你的AWS账户中取消配置你的后端资源!
AWS Amplify允许你使你的Next.js应用程序具有数据、图像存储和认证的全栈功能,而不需要有大量的云或全栈开发知识。