在Node.js GraphQL API上实现AWS S3功能
亚马逊网络服务(AWS)是亚马逊的一个子公司,提供云计算服务。这些服务围绕着存储、应用和基础设施展开。S3是由AWS提供的存储服务。AWS的Node.js SDK(软件开发工具包)使人们能够从Node.js应用程序中访问该平台提供的功能。
另一方面,GraphQL是一个服务器端的运行时间,用于根据在数据上定义的类型系统执行查询,提供查询语言。
目标
在这篇文章中,我们将使用Node.js AWS SDK实现以下s3功能。
- 创建一个s3桶。
- 取回已创建的s3桶。
- 将单个对象上传到s3桶中。
- 将多个对象上传到s3桶中。
- 从s3 bucket获取上传的对象。
- 从s3 bucket中删除单个对象。
- 从s3 bucket中删除多个对象。
- 删除一个s3 bucket。
前提条件
要跟上本文的进度,需要具备以下条件。
- 在你的电脑上安装[Node.js]。
- 在您的计算机上安装[Altair GraphQl客户端]。
- 在你的电脑上安装了[Visual Studio Code]。
- 一个AWS账户。如果你没有,请关注这[篇文章]。
- 具有JavaScript的基本知识。
- 使用[Apollo服务器]实现GraphQL API的基本知识。
获得你的安全凭证
要获得你的安全证书,请遵循以下步骤。
- 前往[AWS控制台]。
- 在右上角,点击
Sign in to the console。 - 输入你的电子邮件地址,然后点击
Next。 - 输入你的密码,然后点击
Sign in。 - 在重定向的页面上,在搜索栏中搜索s3,并点击第一个结果。
- 你将被重定向到你的s3账户页面。
- 在右上方,有你的用户名和一个下拉箭头。点击这里,然后点击
My security credentials。 - 在新页面上,点击
Access keys (access key ID and secret access key)。 - 如果你已经有一个
Access Key ID和一个Secret access key,请自由使用它们。但如果你没有,请点击Create New Access Key按钮。 - 下载
Key File。 - 从当前的URL,你选择你的地区。例如,考虑到这个URL。
https://console.aws.amazon.com/iam/home?region=us-east-2#/security_credentials,区域被设置为us-east-2。 - 在你下载的
Key File,添加以下内容。
region=//the region from the URL. e.g us-east-2
- 设置完地区后,你就可以进行下一步了。
设置开发服务器
在该仓库中,src 目录中,有开始和结束文件夹。在整个文章中,我们将在启动文件夹上工作。如果你遇到错误或想比较你的代码,请随时检查最终文件夹。
从你下载的Key File ,将数据适当地复制到.env 文件中。确保你的名字相匹配,这样就不会有冲突。
在克隆的文件夹中,运行以下命令来安装必要的依赖。
npm install
继续进入开始文件夹,浏览模式文件,了解我们是如何构建数据的。我们在整个文章中的重点将放在resolvers文件夹上。因此,掌握底层模式是有帮助的。
创建一个s3 bucket
一个s3 bucket是s3的基础存储实例。它由文件夹和对象组成。对象就是文件。桶中的数据被存储为文件夹或对象。
为了创建一个bucket,我们在createBucket() 功能下实现以下功能:resolvers/mutation-resolvers.js 。
//create a bucket.
async createBucket(bucketName){
//create an object to hold the name of the bucket.
const params = {
Bucket:bucketName
};
//promisify the createBucket() function so that we can use async/await syntax.
let create_bucket = promisify(this.s3.createBucket.bind(this.s3));
//call the function to create the bucket.
await create_bucket(params).catch(console.log);
//return response to client.
return {
success:true,
message:"Bucket created successfully."
};
};
从上面的实现来看。
-
创建params对象,其键值为
Bucket,以保持桶的名称。 -
从s3答应
createBucket()函数,这样我们就可以使用async/await语法。 -
通过params对象调用
createBucket()函数。 -
送回一个与模式相匹配的响应。
为了测试这一点。
-
按
cmd+shift+\键,在你当前工作目录下打开终端。 -
在弹出的终端中,运行以下命令。
npm run dev
-
打开你的Altair GraphQl客户端。
-
在URL部分,输入控制台中记录的URL。
-
在工作区粘贴以下突变。
mutation CreateBucket {
createBucket(bucketName:"simple-image-upload-bucket"){
message
success
}
}
-
随意改变
bucketName的值。 -
点击播放按钮,检查结果。
-
在创建了一个bucket之后,我们将获取已创建的buckets来验证bucket的创建。
取回已创建的s3桶
在resolvers/query-resolvers.js 中,我们在fetchBuckets() 函数下增加了获取已创建的桶的功能。
//fetching buckets.
async fetchBuckets(){
//promisify the listBuckets() so that we can use the async/await syntax.
const listBuckets = promisify(this.s3.listBuckets.bind(this.s3));
//get the buckets.
let result = await listBuckets().catch(console.log);
//loop through the result extracting only the name of each bucket.
result = result.Buckets.map(result => result.Name);
//return the bucket names as response to the client.
return result;
};
从上面开始。
-
从s3答应
listBuckets()函数,这样我们就可以使用async/await_语法。 -
从s3中获取数据桶。
-
将结果映射到模式中去。
为了测试这个。
-
确保开发仍然在你的终端上运行。
-
前往Altair GraphQl客户端,打开一个不同的标签,并在工作区粘贴以下查询。
query FetchBuckets{
fetchBuckets
}
- 点击播放按钮。新创建的桶应该出现了。
上传单个对象到s3桶中
在确认桶被成功创建后,现在是我们上传一些对象到桶的时候了。这些对象是文件。它们可以是图像、视频、音频、文本,以及更多。在这篇文章中,我们将专注于图像。请自由选择你想要的任何文件。
在resolvers/mutation-resolvers.js ,在uploadObject() 功能下,我们增加了上传单个对象到s3桶的功能。
//upload object.
async uploadObject(file,bucketName){
// create an object to hold the name of the bucket, key, body, and acl of the object.
const params = {
Bucket:bucketName,
Key:'',
Body:'',
ACL:'public-read'
};
// obtain the read stream function and the filename from the file.
let {createReadStream,filename} = await file;
// read the data from the file.
let fileStream = createReadStream();
// in case of an error, log it.
fileStream.on("error", (error) => console.error(error));
// set the body of the object as data to read from the file.
params.Body = fileStream;
// get the current time stamp.
let timestamp = new Date().getTime();
// get the file extension.
let file_extension = extname(filename);
// set the key as a combination of the folder name, timestamp, and the file extension of the object.
params.Key = `images/${timestamp}${file_extension}`;
// promisify the upload() function so that we can use async/await syntax.
let upload = promisify(this.s3.upload.bind(this.s3));
// upload the object.
let result = await upload(params).catch(console.log);
// structure the response.
let object = {
key:params.Key,
url:result.Location
};
// return the response to the client.
return object;
};
从上面的片段来看。
-
创建params对象,包括桶的名称、对象的键、对象的主体和对象的权限。
-
将
createReadStream,并从文件中filename。 -
流入文件的内容。一旦出错,记录错误。
-
将流的内容设置为对象的主体。
-
使用特定的时间戳和其文件扩展名设置对象的键。该对象将被存储在images文件夹中。
-
答应来自s3的
upload()函数,这样我们就可以使用async/await语法。 -
调用发送params对象的函数。我们也从该函数中获得结果。
-
构造一个样本对象以匹配模式输出。
为了测试这一点。
-
确保开发服务器仍在从你的终端运行。
-
前往Altair GraphQl Client,打开一个单独的标签,在工作区粘贴以下突变。
mutation ObjectUpload($object:Upload!) {
uploadObject(file:$object,bucketName:"simple-image-upload-bucket"){
url
key
}
}
-
$Object是我们要从计算机中选择的动态对象,Upload是它在GraphQl中的类型。 -
要选择这个对象,点击下面的
variables。然后点击Add files。在弹出的字段中,将名称从file改为object。然后点击右边的select files,从计算机中选择任何对象。为了与文章保持一致,确保你选择了一张图片。 -
在选择了一个对象后,点击播放按钮并检查结果。
-
为了确认你的对象,在响应被送回后,复制从响应中送回的URL并将其粘贴到你的浏览器。你应该看到你的图像。
将多个对象上传到一个s3桶中
以同样的方式,我们将一个单一的对象上传到s3桶,我们也可以将多个对象上传到s3桶。
在同一个文件中,在uploadObjects() ,我们增加了上传多个对象的功能。
//upload objects.
async uploadObjects(files,bucketName){
// create an object containing the name of the bucket, the key, body, and acl of the object.
let params = {
Bucket:bucketName,
Key:'',
Body:'',
ACL:'public-read'
};
// structure the return data.
let objects = [];
// loop through all the sent files.
for(let i = 0; i < files.length; i++){
// Get that single file.
let file = files[i];
// From the file, get the read stream and the filename.
let {createReadStream,filename} = await file;
// read the data from the file.
let stream = createReadStream();
// in case of any error, log it.
stream.on("error", (error) => console.error(error));
// assign the body of the object to the data to read.
params.Body = stream;
// get the current timestamp.
let timestamp = new Date().getTime();
// get the file extension.
let file_extension = extname(filename);
// compose the key as the folder name, the timestamp, and the file extension of the object.
params.Key = `images/${timestamp}${file_extension}`;
// promisify the upload() function so that we can use async/await syntax.
let upload = promisify(this.s3.upload.bind(this.s3));
// upload the object.
let result = await upload(params).catch(console.log);
// push the structured response to the objects array.
objects.push({
key:params.Key,
url:result.Location
});
};
// return the response to the client.
return objects;
};
从上面开始。
-
创建params对象,包含要上传到的桶,对象的key,对象的body,以及读取文件的权限。
-
初始化一个数组来保存作为响应的数据。
-
循环浏览所有上传的对象。对于每个对象,我们读取其内容,将其设置为主体,获得时间戳和其文件扩展名作为其在图像文件夹中的键。将文件上传到s3桶,然后按照模式重组返回的数据,并将其推送到之前初始化的数组中。
-
返回我们推送到的数组作为输出。
为了测试这个。
-
确保开发服务器仍然在你的终端上运行。
-
前往Altair GraphQl客户端,打开另一个标签,在工作区粘贴以下突变。
mutation ObjectsUpload($objects:[Upload!]!) {
uploadObjects(files:$objects,bucketName:"simple-image-upload-bucket"){
url
key
}
}
-
$objects代表我们从计算机上传的动态对象。它们应该是多个,因此数组的类型是Upload。该数组不应该是空的,而且没有一个文件应该是null。我们还传入要上传到的桶的名称。如果你使用的是一个不同的桶的名字,请随意更改。 -
要选择文件,点击左下角的
Variables,点击Add files。在弹出的字段中,通过简单的点击,将标有1的按钮切换为代表*。将名称从file改为objects。在右边,点击select files。使用你的电脑的command键,选择多个对象。最好是只选择图像。选择后,你会看到你所选择的文件的数量与该领域相邻。 -
点击播放按钮,检查结果。
-
你可以通过访问从浏览器发回的每个URL作为响应来验证这些对象。
从s3桶中获取上传对象
在上传了你的对象之后,你应该能够取回这些对象。
在resolvers/query-resolvers.js ,在fetchObjects() 功能下,我们将实现获取上传对象的功能。
//fetching objects.
async fetchObjects(bucketName){
// create an object to hold the name of the bucket.
const params = {
Bucket:bucketName
};
// promisify the listObjects() function so that we can use the async/await syntax.
let getObjects = promisify(this.s3.listObjects.bind(this.s3));
// get the objects.
let result = await getObjects(params).catch(console.log)
// come up with the array to be returned.
let objects = [];
// Loop through each object returned, structuring the data to be pushed to the objects array.
result.Contents.forEach( content => {
return objects.push({
key:content.Key,
url:getUrl.bind(this,bucketName,content.Key)
})
} );
// return response to the client.
return objects;
};
从上面开始。
-
创建params对象,其键值为
Bucket,代表我们要从其中获取上传对象的桶名。 -
从s3答应
listObjects(),这样我们就可以使用async/await语法了。 -
抓取对象。
-
循环处理发回的结果,按照模式构建数据以匹配样本输出,然后发回结果。
为了测试这一点。
-
确保开发服务器在你的终端上运行。
-
进入Altair GraphQl客户端,打开一个单独的标签,在工作区粘贴以下查询。
query FetchObjects {
fetchObjects(bucketName:"simple-image-upload-bucket"){
url
key
}
}
-
如果你使用的是不同的桶名,请随意更改。
-
点击播放按钮,检查结果。
-
随意复制任何对象的URL,粘贴在浏览器中并查看该对象。
从s3桶中删除一个对象
一旦一个对象不再需要了,为了释放空间,你可以随时从桶中删除它。
在resolvers/mutation-resolvers.js ,在deleteObject() 函数下,我们实现了从s3桶中删除一个对象的功能。
//delete object.
async deleteObject(bucketName,key){
// create an object to hold the name of the bucket, and the key of an object.
const params = {
Bucket:bucketName,
Key: key
};
// promisify the deleteObject() so that we can use the async/await syntax.
let removeObject = promisify(this.s3.deleteObject.bind(this.s3));
// remove the object.
await removeObject(params).catch(console.log);
// send back a response to the client.
return {
success:true,
message:"Object successfully deleted."
};
};
从上面。
-
创建一个params对象,其键值为bucket名称和对象的具体键值。
-
从s3答应
deleteObject(),这样我们就可以使用async/await的语法。 -
删除该对象。
-
按照模式送回响应。
为了测试这个。
-
确保开发服务器仍然在你的终端上运行。
-
前往Altair GraphQl客户端,打开一个单独的标签,并在工作区粘贴以下突变。
mutation DeleteObject {
deleteObject(bucketName:"simple-image-upload-bucket",key:"enter key of the object"){
success
message
}
}
-
在我们获取对象的标签中,从那里复制任何键,并粘贴到
key参数值。 -
如果你使用的是一个单独的桶的名称,请确保你改变这个名称。
-
点击播放按钮,检查结果。
从一个s3桶中删除多个对象
删除多个不再相关的对象,可以释放桶中的空间。
在同一个文件中,在deleteObjects() 功能下,我们实现了删除多个对象的功能。
//delete objects.
async deleteObjects(bucketName,objectKeys){
// create an object to hold the name of the bucket and the objects to be deleted.
const params = {
Bucket:bucketName,
Delete:{
Objects:[]
}
};
// Loop through all the object keys sent pushing them to the params object.
objectKeys.forEach((objectKey) => params.Delete.Objects.push({
Key:objectKey
}));
// promisify the deleteObjects() function so that we can use the async/await syntax.
let removeObjects = promisify(this.s3.deleteObjects.bind(this.s3));
// remove the objects.
await removeObjects(params).catch(console.log);
// send back a response to the server.
return {
success:true,
message:"Successfully deleted objects"
};
};
从上面开始。
-
创建一个params对象,在
Bucketkey下包含要删除的桶的名称,在Deletekey下包含要删除的Objects的数组。 -
循环通过
objectKeys,在params对象中填充Objects数组的关键字Delete。 -
从s3答应
deleteObjects(),这样我们就可以使用async/await语法。 -
删除这些对象。
-
按照模式送回一个响应。
为了测试这个。
-
确保开发服务器已经启动并从你的终端运行。
-
前往Altair GraphQl客户端,打开一个单独的标签,在工作区粘贴以下突变。
mutation DeleteObjects {
deleteObjects(
bucketName:"simple-image-upload-bucket",
objectKeys:["enter_object_key","enter_object_key"]
){
success
message
}
}
-
从获取对象的标签中,复制并粘贴至少两个对象的键到
objectKeys数组中。如果你有更多的对象,请随意包括更多。 -
如果你使用的是一个不同的桶的名字,请确保你改变它。
-
点击播放按钮,检查结果。
删除一个s3 bucket
如果一个s3 bucket已经没有用处了,你可以随时删除它。但是要删除一个s3 bucket,你必须确保里面没有任何对象。否则就会失败。
在同一个文件中,在deleteBucket() 函数下,我们实现了删除一个桶的功能。
//delete bucket.
async deleteBucket(bucketName){
// create an object to hold the name of the bucket.
const params = {
Bucket:bucketName
};
// promisify the deleteBucket() so that we can use the async/await syntax.
let removeBucket = promisify(this.s3.deleteBucket.bind(this.s3));
// remove the bucket.
await removeBucket(params).catch(console.log);
// send back a response to the client.
return {
success:true,
message:"Successfully deleted bucket"
}
};
从上面开始。
-
创建一个params对象,在
Bucket关键下保存要删除的桶的名称。 -
答应
deleteBucket()方法,这样我们就可以使用async/await语法。 -
删除水桶并发回一个响应。
为了测试这个。
-
确保开发服务器在你的终端上运行。
-
前往Altair GraphQl Client,打开一个单独的标签,并在工作区粘贴以下突变。
mutation DeleteBucket {
deleteBucket(bucketName:"enter-a-bucket-name"){
success
message
}
}
-
如果你有一个桶,并且它有文件,通过创建一个s3桶并创建一个假桶。
-
在突变中,在
bucketName值中粘贴其名称。 -
点击播放按钮,检查结果。
总结
到目前为止,AWS S3桶是一个常用的云存储服务。它提供了敏捷性,能够对对象进行各种操作。将对象上传到云存储服务,比用大量数据淹没你的服务器要好。