사전 예방적 스토리지 호환 GraphQL: 직접 업로드
즐거운 사람의 즐거움 코드
나는 즐거운 사람이다.
이런 행복은 다차원적이다. 어떤 차원은 다른 차원보다 더 가치가 있다.
예를 들어, 나는 업무 중에 매우 기뻤다. 왜냐하면 나는 마침내 이런'첨단'프레임을 사용하여 처음부터 하나의 프로젝트를 구축할 기회가 생겼기 때문이다.😉) 기술, asRails 6.
믿든 안 믿든 상관없어. 난 이미 Rails 생산 프로젝트에서 5년 동안 일했어. 심지어 Rails 5를 접촉한 적이 없어. Rails 4밖에 없어!
"유류 Rails 응용 프로그램"은 저의 전문화입니다. (참고로 이것은 제가 곧 개최할 RailsConf 회의의 주제입니다.)
이 암흑시대들은 this January을 끝냈다. 나는
gem install rails --prerelease && rails new ***
을 달렸다.(실제로는
rails new *** -d postgresql --skip-action-mailbox --skip-action-text --skip-action-cable --skip-sprockets --skip-spring --skip-test --skip-bundle
입니다.)내가 하고 있는 프로젝트는 100% 새로운 코드 라이브러리가 아니다.Rails 4를 위해 처음 작성된 코드가 많습니다.
이것은 GraphQL API를 클라이언트(웹 및 모바일 응용 프로그램)의 주요 입구점으로 한다.
낡은 코드 라이브러리를 새로운 응용 프로그램에 이식하는 일부분으로, 우리는 CarrierWave에서 Active Storage으로 이전했다.체험이 순조롭다.비록 Active Storage는 some missing parts이 있지만 그 장점과 Rails 방식의 단순성을 가지고 있다.
주의: Active Storage의 초보자라면 1년 전에 제가 쓴 게시물 "Rails 5.2: Active Storage and beyond"을 보십시오.
따라서 이제는 액티브 저장소의 가장 현저한 장점인 direct uploads으로 전환할 때가 되었다.
유효한 저장 전 수명
우선 Rails 4에서 파일 업로드를 처리하는 방법을 알려드릴게요.GraphQL 규범과
graphql
Ruby gem은 올바른 요리 파일을 업로드하는 방법을 지정하지 않았습니다.open-source specification이 있는데 Ruby을 포함하여 서로 다른 언어의 실현이 있다.이것은
Upload
표량 유형을 묘사하고 Rack middleware 마술을 하여 업로드된 파일을 변수로 전달하고 약간 투명하다.듣자니 "끼워 넣자마자 쓰기"인 것 같다이론상실천에서 이는'꽂기만 하면 n-fail-n-fix-n-fail-n-fix'로 바뀐다.
Upload
type(실제 대상 유형에 무관심)으로 인한 부작용 여기에 직접 업로드하는 이벤트 저장소가 있습니다.
부트 업로드🎥
그나저나'바로 업로드'가 뭐예요?
이 용어는 일반적으로 클라우드 저장소 서비스(예를 들어 Amazon S3)와 결합하여 사용하는데 그 의미는 다음과 같다. 클라이언트가 API 서버를 사용하여 생성한 증빙서류를 사용하여 파일을 클라우드 저장소에 직접 업로드하는 것이지 API 서버를 사용하여 파일을 업로드하는 것이 아니다.
직접 업로드
좋은 소식 – Active Storage는 직접 업로드를 처리하는 서버 측 API 및 프런트엔드 JS 클라이언트 out-of-the-box을 제공합니다.
또 다른 좋은 소식은 이 API는 추상적이며 활성 저장소가 지원하는 service(파일 시스템, S3, GCloud, Azure)에 적용된다는 것이다.이것은 매우 좋습니다. 로컬에서 파일 시스템을 사용할 수 있습니다. 생산 과정에서 S3를 사용할 수 있습니다. 모든
if
-s와 else-
-s가 필요하지 않습니다.그럼에도 불구하고 좋은 소식은 항상 나쁜 소식을 수반한다.나쁜 소식은 활성 저장소 (일반 Rails) 가 GraphQL에 대해 아무것도 모르고, 직접 업로드 자격 증명을 검색하기 위해 자체 RESTAPI에 의존한다는 것이다.
GraphQL에서 이 모든 것을 실현하려면 어떻게 해야 합니까?
우선 GraphQL API(mutation)를 사용하여 직접 업로드 자격 증명을 얻을 수 있습니다.
그 다음으로 가능한 한 프레임워크의 자바스크립트 코드를 많이 다시 사용해서 바퀴의 중복 발명을 피하는 것이 좋다.
createDirectUpload 변이...
GraphiQL의 돌변 미리보기
불행하게도 Rails는 서버 측에서 직접 실행된 문서를 업로드하지 않았습니다.
source code,
DirectUploadsController
:def create
blob = ActiveStorage::Blob.create_before_direct_upload!(blob_args)
render json: direct_upload_json(blob)
end
private
def blob_args
params.require(:blob).permit(:filename, :byte_size, :checksum, :content_type, :metadata).to_h.symbolize_keys
end
def direct_upload_json(blob)
blob.as_json(root: false, methods: :signed_id).merge(direct_upload: {
url: blob.service_url_for_direct_upload,
headers: blob.service_headers_for_direct_upload
})
end
checksum
파라미터를 보십시오. 이것은 활성 저장소에 숨겨진 보석 중 하나입니다. 내장된 파일 내용 검증입니다.클라이언트가 직접 업로드를 요청할 때 파일의 검증 및 (MD5 해시 인코딩 Base64) 을 지정할 수 있으며, 서비스 (예: 활성 메모리 자체 또는 S3) 는 나중에 이 검사 및 를 사용하여 업로드된 파일의 내용을 검증합니다.
GraphQL로 돌아가겠습니다.
GraphQL 돌연변이는 Rails 컨트롤러와 매우 유사하기 때문에 상기 코드를 돌연변이로 전환하는 것은 매우 간단하다.
class CreateDirectUpload < GraphQL::Schema::Mutation
class CreateDirectUploadInput < GraphQL::Schema::InputObject
description "File information required to prepare a direct upload"
argument :filename, String, "Original file name", required: true
argument :byte_size, Int, "File size (bytes)", required: true
argument :checksum, String, "MD5 file checksum as base64", required: true
argument :content_type, String, "File content type", required: true
end
argument :input, CreateDirectUploadInput, required: true
class DirectUpload < GraphQL::Schema::Object
description "Represents direct upload credentials"
field :url, String, "Upload URL", null: false
field :headers, String,
"HTTP request headers (JSON-encoded)",
null: false
field :blob_id, ID, "Created blob record ID", null: false
field :signed_blob_id, ID,
"Created blob record signed ID",
null: false
end
field :direct_upload, DirectUpload, null: false
def resolve(input:)
blob = ActiveStorage::Blob.create_before_direct_upload!(input.to_h)
{
direct_upload: {
url: blob.service_url_for_direct_upload,
# NOTE: we pass headers as JSON since they have no schema
headers: blob.service_headers_for_direct_upload.to_json,
blob_id: blob.id,
signed_blob_id: blob.signed_id
}
}
end
end
# add this mutation to your Mutation type
field :create_direct_upload, mutation: CreateDirectUpload
이제 서버에서 직접 업로드 로드를 검색하려면 GraphQL 클라이언트가 다음 요청을 수행해야 합니다.mutation {
createDirectUpload(input: {
filename: "dev.to", # file name
contentType: "image/jpeg", # file content type
checksum: "Z3Yzc2Q5iA5eXIgeTJn", # checksum
byteSize: 2019 # size in bytes
}) {
directUpload {
signedBlobId
}
}
}
...JavaScript도 있습니다.
면책 성명: 아래 JS 구현은 단지 초도일 뿐, 아직 현실에서 테스트한 적이 없습니다(제 프로젝트에서 Rails의 JS 코드를 사용하지 않았기 때문).내가 검사한 것은 단지 그것의 번역일 뿐이다.
파일을 업로드하려면 클라이언트가 다음 단계를 수행해야 합니다.
createDirectUpload
변이 "@rails/activestorage"
을 package.json
에 추가하는 것을 잊지 마십시오).getFileMetadata
함수를 작성합니다.import { FileChecksum } from "@rails/activestorage/src/file_checksum";
function calculateChecksum(file) {
return new Promise((resolve, reject) => {
FileChecksum.create(file, (error, checksum) => {
if (error) {
reject(error);
return;
}
resolve(checksum);
});
});
}
export const getFileMetadata = (file) => {
return new Promise((resolve) => {
calculateChecksum(file).then((checksum) => {
resolve({
checksum,
filename: file.name,
content_type: file.type,
byte_size: file.size
});
});
});
};
FileChecksum
클래스는 계산에 필요한 검사와 검사를 책임지고 DirectUpload
클래스의 활성 메모리에서 사용한다.이제 이 함수를 사용하여 GraphQL 쿼리 로드를 구성할 수 있습니다.
// pseudo code
getFileMetadata(file).then((input) => {
return performQuery(
CREATE_DIRECT_UPLOAD_QUERY,
variables: { input }
);
});
파일을 저장 서비스에 직접 업로드하는 함수를 작성할 때입니다!import { BlobUpload } from "@rails/activestorage/src/blob_upload";
export const directUpload = (url, headers, file) => {
const upload = new BlobUpload({ file, directUploadData: { url, headers } });
return new Promise((resolve, reject) => {
upload.create(error => {
if (error) {
reject(error);
} else {
resolve();
}
})
});
};
전체 클라이언트 코드의 예는 다음과 같습니다.getFileMetadata(file).then((input) => {
return performQuery(
CREATE_DIRECT_UPLOAD_QUERY,
variables: { input }
).then(({ directUpload: { url, headers, signedBlobId }) => {
return directUpload(url, JSON.parse(headers), file).then(() => {
// do smth with signedBlobId – our file has been uploaded!
});
});
});
우리가 해냈구나!새로운 Rails+GraphQL 프로젝트를 구축하는 데 도움이 되었으면 합니다.)For more realistic example, check out this snippet from our React Native application: https://gist.github.com/Saionaro/7ee0e2c02749e2729dc429c9e9bfa7f3
어쨌든, 또는 signedBlobId를 어떻게 처리하는지
응용 프로그램에서 서명blob id-
attachProfileAvatar
변이를 어떻게 사용하는지 간단한 예를 들겠습니다.class AttachProfileAvatar < GraphQL::Schema::Mutation
description <<~DESC
Update the current user's avatar
(by attaching a blob via signed ID)
DESC
argument :blob_id, String,
"Signed blob ID generated via `createDirectUpload` mutation",
required: true
field :user, Types::User, null: true
def resolve(blob_id:)
# Active Storage retrieves the blob data from DB
# using a signed_id and associates the blob with the attachment (avatar)
current_user.avatar.attach(blob_id)
{user: current_user}
end
end
그렇습니다!https://evilmartians.com/chronicles에 대한 더 많은 개발 글을 읽으세요!
Reference
이 문제에 관하여(사전 예방적 스토리지 호환 GraphQL: 직접 업로드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/evilmartians/active-storage-meets-graphql-direct-uploads-3n38텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)