Simple library implementation to put in practice the Google API design guide.
Start the API:
make run/api
curl localhost:8081/v1/shelves/shelf1/books -d'{ "name": "book1", "author": "Henrod", }'
or
grpcurl -d '{ "parent": "shelves/shelf1", "book": { "name": "shelves/shelf1/books/book1", "author": "Henrod" } }' \ -plaintext localhost:8080 api.v1.LibraryService/CreateBook
{
"name": "shelves/shelf1/books/book1",
"author": "Henrod",
"createTime": "2022年01月21日T00:02:34.045823Z",
"updateTime": "2022年01月21日T00:02:34.045823Z"
}{
"code": 6,
"message": "resource already exists",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "book",
"resourceName": "book1",
"owner": "shelves/shelf1",
"description": "the book already exists in shelf"
}
]
}curl localhost:8081/v1/shelves/shelf1/books/book1
or
grpcurl -d '{"name": "shelves/shelf1/books/book1"}' \
api.v1.LibraryService/ListBooks{
"books": [
{
"name": "shelves/shelf1/books/book1",
"author": "Henrod",
"createTime": "2022年01月20日T11:01:42.327988Z",
"updateTime": "2022年01月20日T11:01:42.327988Z"
}
],
"nextPageToken": ""
}{
"code": 5,
"message": "resource not found",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "book",
"resourceName": "shelves/shelf1/books/book2",
"owner": "shelf1",
"description": "the book does not exist in shelf"
}
]
}curl localhost:8081/v1/shelves/shelf1/books
or
grpcurl -d '{"parent": "shelves/shelf1"}' \
-plaintext localhost:8080 api.v1.LibraryService/ListBooks{
"books": [
{
"name": "shelves/shelf1/books/book1",
"author": "Henrod",
"createTime": "2022年01月20日T11:01:42.327988Z",
"updateTime": "2022年01月22日T21:57:56.011468Z"
},
{
"name": "shelves/shelf1/books/book2",
"author": "Henrod",
"createTime": "2022年01月21日T00:02:34.045823Z",
"updateTime": "2022年01月22日T21:59:41.508003Z"
}
],
"nextPageToken": ""
}curl localhost:8081/v1/shelves/shelf1/books\?page_size=1or
grpcurl -d '{"parent": "shelves/shelf1", "page_size": 1}' \
-plaintext localhost:8080 api.v1.LibraryService/ListBooks{
"books": [
{
"name": "shelves/shelf1/books/book1",
"author": "Henrod",
"createTime": "2022年01月20日T11:01:42.327988Z",
"updateTime": "2022年01月20日T11:01:42.327988Z"
}
],
"nextPageToken": "MQ=="
}curl localhost:8081/v1/shelves/shelf1/books\?page_size=1\&page_token=MQ==
or
grpcurl -d '{ "parent": "shelves/shelf1", "page_size": 1, "page_token": "MQ==" }' \ -plaintext localhost:8080 api.v1.LibraryService/ListBooks
{
"books": [
{
"name": "shelves/shelf1/books/book2",
"author": "Henrod",
"createTime": "2022年01月21日T00:02:29.938371Z",
"updateTime": "2022年01月21日T00:02:29.938371Z"
}
],
"nextPageToken": ""
}curl localhost:8081/v1/shelves/-/books
or
grpcurl -d '{"parent": "shelves/-"}' \
-plaintext localhost:8080 api.v1.LibraryService/ListBooks{
"books": [
{
"name": "shelves/shelf1/books/book1",
"author": "Henrod",
"createTime": "2022年01月20日T11:01:42.327988Z",
"updateTime": "2022年01月22日T21:57:56.011468Z"
},
{
"name": "shelves/shelf2/books/book1",
"author": "Henrod",
"createTime": "2022年01月21日T00:02:34.045823Z",
"updateTime": "2022年01月22日T21:59:41.508003Z"
}
],
"nextPageToken": ""
}curl localhost:8081/v1/shelves/shelf1/books/book1 -XPATCH -d'{ "author": "Henrique Rodrigues" }'
or
grpcurl -d '{ "book": { "name": "shelves/shelf1/books/book1", "author": "Henrique Rodrigues" }, "update_mask": { "paths": ["author"] } }' \ -plaintext localhost:8080 api.v1.LibraryService/UpdateBook
{
"name": "shelves/shelf1/books/book1",
"author": "Henrique Rodrigues",
"createTime": "2022年01月20日T11:01:42.327988Z",
"updateTime": "2022年01月22日T21:57:56.011468Z"
}{
"code": 5,
"message": "resource not found",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "book",
"resourceName": "shelves/shelf1/books/book3",
"owner": "shelves/shelf1",
"description": "book not found in shelf"
}
]
}curl localhost:8081/v1/shelves/shelf1/books/book1 -XPATCH -d'{ "invalid_field": "anything" }'
or
grpcurl -d '{ "book": { "name": "shelves/shelf1/books/book1", "invalid_field": "anything" }, "update_mask": { "paths": ["invalid_field"] } }' \ -plaintext localhost:8080 api.v1.LibraryService/UpdateBook
HTTP
{
"code": 3,
"message": "could not find field \"invalid_field\" in \"api.v1.Book\"",
"details": []
}gRPC
Error invoking method "api.v1.LibraryService/UpdateBook": error getting request data: message type api.v1.Book has no known field named invalid_field
curl localhost:8081/v1/shelves/shelf1/books/book1 -XDELETE
or
grpcurl -d '{ "name": "shelves/shelf1/books/book1" }' \
-plaintext localhost:8080 api.v1.LibraryService/DeleteBook{}{
"code": 5,
"message": "resource not found",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "book",
"resourceName": "shelves/shelf1/books/book2",
"owner": "shelves/shelf1",
"description": "book not found in shelf"
}
]
}Asynchronous operation. Returns a long-running operation resource, which is used by the client to poll the status.
curl localhost:8081/v1/shelves -d'{"name": "shelf1"}'or
grpcurl -d '{ "name": "shelf1" }' \
-plaintext localhost:8080 api.v1.LibraryService/CreateShelf{
"done": false,
"metadata": {
"@type": "type.googleapis.com/api.v1.Operation",
"name": "CreateShelf",
"percentage": 0,
"stage": "PLANTING_TREE"
},
"name": "operations/shelves/shelf1"
}{
"code": 6,
"message": "resource already exists",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "operation",
"resourceName": "operations/shelves/shelf3",
"owner": "library",
"description": "the create shelf operation already exists"
}
]
}Get the status of a long-running operation. Currently, only supports:
- CreateShelf
curl localhost:8081/v1/operations/shelves/shelf1
or
grpcurl -d '{ "name": "operations/shelves/shelf1" }' \
-plaintext localhost:8080 api.v1.LibraryService/GetOperation{
"done": false,
"metadata": {
"@type": "type.googleapis.com/api.v1.Operation",
"name": "CreateShelf",
"percentage": 0,
"stage": "PLANTING_TREE"
},
"name": "operations/shelves/shelf1"
}{
"name": "operations/shelves/shelf1",
"metadata": {
"@type": "type.googleapis.com/api.v1.Operation",
"name": "CreateShelf",
"stage": "FINISHED_SHELF",
"percentage": 100
},
"done": true,
"response": {
"@type": "type.googleapis.com/api.v1.Shelf",
"name": "shelves/shelf1",
"createTime": "2022年02月13日T21:25:09.034864Z",
"updateTime": "2022年02月13日T21:25:09.034864Z"
}
}{
"name": "operations/shelves/shelf1",
"metadata": {
"@type": "type.googleapis.com/api.v1.Operation",
"name": "CreateShelf",
"stage": "FINISHED_SHELF",
"percentage": 100
},
"done": true,
"error": {
"code": 6,
"message": "resource already exists",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "shelf",
"resourceName": "shelves/shelf1",
"owner": "library",
"description": "the shelf already exists in the library"
}
]
}
}{
"code": 5,
"message": "resource not found",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ResourceInfo",
"resourceType": "operation",
"resourceName": "operations/shelves/shelf1",
"owner": "library",
"description": "the operation doesn't exist; is not running nor completed"
}
]
}