리소스 중심 API에서 리소스는 이름이 지정된 개체이고, 리소스 이름은 식별자입니다. 리소스마다 고유한 리소스 이름이 있어야 합니다. 리소스 이름은 리소스 자체의 ID와 상위 리소스의 ID, 그리고 API 서비스 이름으로 구성됩니다. 여기에서는 리소스 ID와 리소스 이름의 작성 방법에 대해서 살펴보겠습니다.
gRPC API는 리소스 이름에 스키마가 따로 정의되지 않은 URI를 사용해야 합니다. 이 URI는 일반적으로 REST URL 규칙을 따를 뿐만 아니라 동작도 네트워크 파일 경로와 매우 비슷합니다. 또한 REST URL로 매핑도 매우 쉽습니다. 자세한 내용은 표준 메서드 섹션을 참조하세요.
컬렉션은 특별한 리소스로서 동일한 유형의 하위 리소스 목록이 여기에 포함됩니다. 예를 들어 디렉터리는 파일 리소스의 컬렉션입니다. 컬렉션을 나타내는 리소스 ID는 컬렉션 ID라고 부릅니다.
리소스 이름은 슬래시로 구분된 컬렉션 ID와 리소스 ID를 사용해 계층적으로 구성됩니다. 리소스에 하위 리소스가 포함되어 있는 경우에는 하위 리소스의 이름이 마찬가지로 슬래시로 구분된 상위 리소스 이름과 하위 리소스의 ID를 차례로 지정하여 구성됩니다.
예시 1: 스토리지 서비스에는 buckets
컬렉션이 있고 이 컬렉션의 각 버킷에는 objects
컬렉션이 있습니다.
API 서비스 이름 | 컬렉션 ID | 리소스 ID | 컬렉션 ID | 리소스 ID |
---|---|---|---|---|
//storage.googleapis.com | /buckets | /bucket-id | /objects | /object-id |
예시 2: 이메일 서비스에는 users
컬렉션이 있습니다. 각 사용자에게는 settings
하위 리소스가 있고 settings
하위 리소스에는 customFrom
을 포함하여 다른 하위 리소스가 여러 개 있습니다.
API 서비스 이름 | 컬렉션 ID | 리소스 ID | 리소스 ID | 리소스 ID |
---|---|---|---|---|
//mail.googleapis.com | /users | /name@example.com | /settings | /customFrom |
API 작성자는 리소스 계층 구조 내에서 고유성을 유지할 수만 있다면 리소스 및 컬렉션 ID에 허용되는 값을 선택할 수 있습니다. 리소스 및 컬렉션 ID의 올바른 선택에 대한 자세한 가이드라인은 아래에서 찾아볼 수 있습니다.
슬래시가 포함된 세그먼트가 없다는 가정 하에서 name.split("/")[n]
과 같이 리소스 이름을 분할하면 컬렉션 ID와 리소스 ID를 각각 구할 수 있습니다.
전체 리소스 이름
스키마가 따로 정의되지 않은 URI는 DNS 호환 API 서비스 이름과 리소스 경로로 구성됩니다. 리소스 이름은 상대적 리소스 이름으로도 알려져 있습니다. 예를 들면 다음과 같습니다.
"//library.googleapis.com/shelves/shelf1/books/book2"
API 서비스 이름은 클라이언트가 API 서비스 엔드포인트를 찾는 데 필요하기 때문에 내부 전용 서비스를 위한 가짜 DNS 이름이 될 수도 있습니다. API 서비스 이름이 컨텍스트에서 명확한 경우 상대적 리소스 이름이 사용되는 경우도 많습니다.
상대적 리소스 이름
선행 '/'가 없는 URI 경로(path-noscheme)입니다. 이 이름은 API 서비스 내에서 리소스를 식별하는 데 사용됩니다. 예를 들면 다음과 같습니다.
"shelves/shelf1/books/book2"
리소스 ID
리소스 ID는 일반적으로 상위 리소스 내에서 리소스를 식별하는 하나 이상의 비어 있지 않은 URI 세그먼트(segment-nz-nc)로 구성됩니다. 위 예시를 참조하세요. 리소스 이름에서 후행하지 않는 리소스 ID는 정확히 1개의 URL 세그먼트를 가져야 하지만, 리소스 이름에서 후행하는 리소스 ID는 2개 이상의 URI 세그먼트를 가질 수 있습니다. 예를 들면 다음과 같습니다.
컬렉션 ID | 리소스 ID |
---|---|
파일 | source/py/parser.py |
API 서비스는 가능하다면 URL 친화적인 리소스 ID를 사용해야 합니다. 리소스 ID가 클라이언트, 서버, 또는 둘 다에서 할당되었는지 쉽게 알 수 있도록 명시해야 합니다. 예를 들어 파일 이름은 일반적으로 클라이언트에서 할당되고, 이메일 메시지 ID는 서버에서 할당됩니다.
컬렉션 ID
상위 리소스 내에서 컬렉션 리소스를 식별하기 위해 비어있지 않은 URI 세그먼트(segment-nz-nc)이며, 위의 예를 참조하세요.
컬렉션 ID는 생성된 클라이언트 라이브러리에 표시되는 경우가 많기 때문에 다음과 같은 요구 사항을 따라야 합니다.
- 유효한 C/C++ 식별자가 되어야 합니다.
- 복수 형태로 lowerCamel 표기법을 따라야 합니다. 'evidence' 및 'weather'와 같이 적절한 복수 형태가 없는 경우에는 단수 형태를 사용해야 합니다.
- 명확하고 간결한 영어 용어를 사용해야 합니다.
- 지나치게 일반적인 용어의 사용은 피하고, 그럴 수 없는 경우에는 적합해야 합니다. 예를 들어
values
보다rowValues
를 사용하는 것이 좋습니다. 다음 용어의 사용이 적합하지 않을 경우 피해야 합니다.- elements
- entries
- instances
- items
- objects
- resources
- types
- values
리소스 이름과 URL의 비교
전체 리소스 이름이 일반적인 URL과 비슷하다고 해서 동일한 것은 아닙니다. API 버전, API 프로토콜 또는 API 네트워크 엔드포인트마다 단일 리소스를 제공할 수 있습니다. 하지만 전체 리소스 이름은 이러한 정보를 지정하지 않기 때문에 실제로 사용하기 위해서는 특정 API 버전 및 API 프로토콜에 매핑되어야 합니다.
REST API를 통해 전체 리소스 이름을 사용하려면 서비스 이름 앞에 HTTPS 스키마를 추가하고, 리소스 경로 앞에 API 주 버전을 추가하고, 리소스 경로에 URL 이스케이프 문자를 사용하여 REST URL로 변환해야 합니다. 예를 들면 다음과 같습니다.
// This is a calendar event resource name.
"//calendar.googleapis.com/users/john smith/events/123"
// This is the corresponding HTTP URL.
"https://calendar.googleapis.com/v3/users/john%20smith/events/123"
문자열 형식의 리소스 이름
Google API에서는 하위 호환성이 중요한 문제가 아니라면 평문 문자열을 사용해 리소스 이름을 나타내야 합니다. 리소스 이름은 일반적인 파일 경로처럼 처리되어야 합니다. 리소스 이름이 여러 구성요소 간에 전송되는 경우 원자 값으로 처리되어야 하며 데이터 손실이 있어서는 안 됩니다.
리소스를 정의할 때 첫 번째 필드는 리소스 이름을 나타내는 문자열 필드여야 하며 이 필드 이름은 name
이어야 합니다.
예를 들면 다음과 같습니다.
service LibraryService {
rpc GetBook(GetBookRequest) returns (Book) {
option (google.api.http) = {
get: "/v1/{name=shelves/*/books/*}"
};
};
rpc CreateBook(CreateBookRequest) returns (Book) {
option (google.api.http) = {
post: "/v1/{parent=shelves/*}/books"
body: "book"
};
};
}
message Book {
// Resource name of the book. It must have the format of "shelves/*/books/*".
// For example: "shelves/shelf1/books/book2".
string name = 1;
// ... other properties
}
message GetBookRequest {
// Resource name of a book. For example: "shelves/shelf1/books/book2".
string name = 1;
}
message CreateBookRequest {
// Resource name of the parent resource where to create the book.
// For example: "shelves/shelf1".
string parent = 1;
// The Book resource to be created. Client must not set the `Book.name` field.
Book book = 2;
}
참고: 리소스 이름의 일관성을 위해 URL 템플릿 변수에 선행 슬래시를 표현해서는 안 됩니다. 예를 들어 "/v1{name=/shelves/*/books/*}"
대신 URL 템플릿 "/v1/{name=shelves/*/books/*}"
를 사용해야 합니다.
질문
Q: 리소스 식별을 위해 리소스 ID를 사용하지 않는 이유는 무엇입니까?
대규모 시스템에는 수많은 종류의 리소스가 있습니다. 리소스 ID를 사용하여 리소스를 식별하려면 실제로 (bucket, object)
또는 (user, album, photo)
와 같은 리소스별 튜플을 사용하여 리소스를 식별합니다. 하지만 이렇게 할 경우 다음과 같이 커다란 문제를 초래합니다.
- 개발자가 이러한 익명의 튜플을 이해하고 기억해야 합니다.
- 일반적으로 튜플은 문자열보다 전달하기 더욱 어렵습니다.
- 로깅 시스템이나 액세스 제어 시스템 같은 중앙 인프라는 전용 튜플을 이해하지 못합니다.
- 전용 튜플은 재사용이 가능한 API 인터페이스를 제공하는 등 API의 디자인 유연성을 제한합니다. 예를 들어 장기 실행 작업은 유연한 리소스 이름을 사용하기 때문에 여러 가지 다른 API 인터페이스와 호환될 수 있습니다.
Q: 리소스 이름 필드가 id
가 아닌 name
으로 불리는 이유는 무엇인가요?
리소스 이름 필드의 이름은 리소스 '이름'이라는 개념에 따른 것입니다. 일반적으로 name
의 개념은 개발자에게 혼동을 일으키기 쉽습니다. 예를 들어 파일 이름은 이름만을 나타낼까요? 아니면 전체 경로를 나타낼까요? 표준 필드 name
은 예약되어 있으므로 개발자는 display_name
또는 title
또는 full_name
과 같은 더욱 적절한 단어를 선택해야 합니다.
Q: 리소스 이름을 생성하고 파싱하려면 어떻게 해야 하나요?
리소스 이름은 파일 경로처럼 작동합니다. printf()
를 사용하여 리소스 ID에서 리소스 이름을 생성할 수 있습니다. split()
을 사용하여 리소스 이름을 리소스 ID로 파싱할 수 있습니다. 일부 후행 리소스 ID에는 파일 경로와 같이 /
로 구분된 여러 URI 세그먼트가 있을 수 있습니다.