Autogenerate services.m3o.com (#37)

* Autogenerate services.m3o.com

* Openapi for all

* Gen

* Fix

* Whaat

* Fix dep

* Fix

* Hmm

* Install make

* Debug

* Debug 1

* Location -> locations

* Fix

* Intall protoc gen micro

* F

* F

* F

* Push

* Rename secret

* Fix npm install

* Fix script

* Fix v2

* Ignore errors

* Ignore v2

* F

* F

* F

* Docs index

* Add hugo theme

* Hugo tania fixes

* Change gen

* Change gen 2

* Install hugo

* Change gen

* Gen fix

* Change hugo install

* Change hugo install

* CNAME

* Change articles wording

* Tiny fix

* Fix gen

* Redoc it all

* Fix gen

* Fixing up protos

* Fix proto

* Fix gen

* Fix

* Trigger build

* Fix copy

* Openapi docs

* Flatten

* Changes

* No date vol2

* Changes

* Add make to chat

* Fixes

* Change

* api spec

* replace RSS

* fix link

* Dont continue on error

* increase the width

* use micro at master

* change box colours

* move some things

* Pushing new readmes to see how they look like

* Add skip file

* Readmes

* Nicer api link

* Remove stutter

* FIx mistake

* set service font weight

* Messages readme fix

* add other font bold

* Notes

* Remove post from url

* Revert "Remove post from url"

This reverts commit 5fea2c23d0bafa910f5dc4d4cc63f71f578530e3.

* move exampleSite to site

* replace exampleSite with site

* update readme

* use filename for post

* update index

* Add source urls

* set source as params

* set source as params

* Fix entries

* Generator in go

* Fixes to generator

* F

* Change doc gen

* FIx cname

* Fixing protos

* Change to makefiles

* Fix gen script

Co-authored-by: Asim Aslam <asim@aslam.me>
This commit is contained in:
Janos Dobronszki
2021-01-19 16:59:25 +00:00
committed by GitHub
parent ec81db0753
commit 40b71a9cf9
174 changed files with 10914 additions and 3157 deletions

2
posts/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
./posts

3
posts/Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
ADD post-service /post-service
ENTRYPOINT [ "/post-service" ]

27
posts/Makefile Normal file
View File

@@ -0,0 +1,27 @@
GOPATH:=$(shell go env GOPATH)
MODIFY=Mgithub.com/micro/micro/proto/api/api.proto=github.com/micro/micro/v3/proto/api
.PHONY: proto
proto:
protoc --openapi_out=. --proto_path=. --micro_out=${MODIFY}:. --go_out=${MODIFY}:. proto/posts.proto
.PHONY: docs
docs:
protoc --openapi_out=. --proto_path=. --micro_out=${MODIFY}:. --go_out=${MODIFY}:. proto/posts.proto
@redoc-cli bundle api-posts.json
.PHONY: build
build: proto
go build -o post-service *.go
.PHONY: test
test:
go test -v ./... -cover
.PHONY: docker
docker:
docker build . -t post-service:latest

90
posts/README.md Normal file
View File

@@ -0,0 +1,90 @@
The post service is responsible for storing and querying posts by their slugs or IDs. Posts support tags and metadata, for details see `posts.proto`.
# Post Service
## Create a post
### cURL
```shell
> curl 'https://api.m3o.com/posts/Save' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{"post":{"id":"1","title":"How to Micro","content":"Simply put, Micro is awesome."}}';
> curl 'https://api.m3o.com/chat/Save' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{"post":{"id":"2","title":"Fresh posts are fresh","content":"This post is fresher than the How to Micro one"}}';
```
### CLI
```shell
micro call posts Posts.Save '{"post":{"id":"1","title":"How to Micro","content":"Simply put, Micro is awesome."}}'
micro call posts Posts.Save '{"post":{"id":"2","title":"Fresh posts are fresh","content":"This post is fresher than the How to Micro one"}}'
```
## Create a post with tags
### cURL
```shell
> curl 'https://api.m3o.com/posts/Save' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{"post":{"id":"3","title":"How to do epic things with Micro","content":"Everything is awesome.","tagNames":["a","b"]}}';
```
### CLI
```shell
micro call posts Posts.Save '{"post":{"id":"3","title":"How to do epic things with Micro","content":"Everything is awesome.","tagNames":["a","b"]}}'
```
## Query posts
### cURL
```shell
# Query all
> curl 'https://api.m3o.com/posts/Query' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{}';
# Query by slug
> curl 'https://api.m3o.com/posts/Query' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{"slug":"how-to-micro"}';
# Limit and offset
> curl 'https://api.m3o.com/posts/Query' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{"offset": 10, "limit": 10}';
```
### CLI
```shell
micro call posts Posts.Query '{}'
micro call posts Posts.Query '{"slug":"how-to-micro"}'
micro call posts Posts.Query '{"offset": 10, "limit": 10}'
```
## Delete posts
```shell
> curl 'https://api.m3o.com/posts/Delete' \
-H 'micro-namespace: $yourNamespace' \
-H 'authorization: Bearer $yourToken' \
-d '{"id": "3c9ea66c"}';
```
```shell
micro call posts Posts.Delete '{"id": "3c9ea66c"}'
```

3
posts/generate.go Normal file
View File

@@ -0,0 +1,3 @@
package main
//go:generate make proto

View File

@@ -0,0 +1,738 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.6.1
// source: proto/posts.proto
package posts
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Post struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Slug string `protobuf:"bytes,3,opt,name=slug,proto3" json:"slug,omitempty"`
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
Created int64 `protobuf:"varint,5,opt,name=created,proto3" json:"created,omitempty"`
Updated int64 `protobuf:"varint,6,opt,name=updated,proto3" json:"updated,omitempty"`
Author string `protobuf:"bytes,7,opt,name=author,proto3" json:"author,omitempty"`
Tags []string `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"`
Metadata map[string]string `protobuf:"bytes,9,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Image string `protobuf:"bytes,19,opt,name=image,proto3" json:"image,omitempty"`
}
func (x *Post) Reset() {
*x = Post{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Post) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Post) ProtoMessage() {}
func (x *Post) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Post.ProtoReflect.Descriptor instead.
func (*Post) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{0}
}
func (x *Post) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *Post) GetTitle() string {
if x != nil {
return x.Title
}
return ""
}
func (x *Post) GetSlug() string {
if x != nil {
return x.Slug
}
return ""
}
func (x *Post) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
func (x *Post) GetCreated() int64 {
if x != nil {
return x.Created
}
return 0
}
func (x *Post) GetUpdated() int64 {
if x != nil {
return x.Updated
}
return 0
}
func (x *Post) GetAuthor() string {
if x != nil {
return x.Author
}
return ""
}
func (x *Post) GetTags() []string {
if x != nil {
return x.Tags
}
return nil
}
func (x *Post) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *Post) GetImage() string {
if x != nil {
return x.Image
}
return ""
}
// Query posts. Acts as a listing when no id or slug provided.
// Gets a single post by id or slug if any of them provided.
type QueryRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"`
Tag string `protobuf:"bytes,3,opt,name=tag,proto3" json:"tag,omitempty"`
Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
Limit int64 `protobuf:"varint,5,opt,name=limit,proto3" json:"limit,omitempty"`
}
func (x *QueryRequest) Reset() {
*x = QueryRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QueryRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QueryRequest) ProtoMessage() {}
func (x *QueryRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QueryRequest.ProtoReflect.Descriptor instead.
func (*QueryRequest) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{1}
}
func (x *QueryRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *QueryRequest) GetSlug() string {
if x != nil {
return x.Slug
}
return ""
}
func (x *QueryRequest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *QueryRequest) GetOffset() int64 {
if x != nil {
return x.Offset
}
return 0
}
func (x *QueryRequest) GetLimit() int64 {
if x != nil {
return x.Limit
}
return 0
}
type QueryResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"`
}
func (x *QueryResponse) Reset() {
*x = QueryResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QueryResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QueryResponse) ProtoMessage() {}
func (x *QueryResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QueryResponse.ProtoReflect.Descriptor instead.
func (*QueryResponse) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{2}
}
func (x *QueryResponse) GetPosts() []*Post {
if x != nil {
return x.Posts
}
return nil
}
type SaveRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Slug string `protobuf:"bytes,3,opt,name=slug,proto3" json:"slug,omitempty"`
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
Timestamp int64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// When updating a post and wanting to delete all tags,
// send a list of tags with only one member being an empty string [""]
Tags []string `protobuf:"bytes,6,rep,name=tags,proto3" json:"tags,omitempty"`
Metadata map[string]string `protobuf:"bytes,7,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Image string `protobuf:"bytes,8,opt,name=image,proto3" json:"image,omitempty"`
}
func (x *SaveRequest) Reset() {
*x = SaveRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SaveRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SaveRequest) ProtoMessage() {}
func (x *SaveRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SaveRequest.ProtoReflect.Descriptor instead.
func (*SaveRequest) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{3}
}
func (x *SaveRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *SaveRequest) GetTitle() string {
if x != nil {
return x.Title
}
return ""
}
func (x *SaveRequest) GetSlug() string {
if x != nil {
return x.Slug
}
return ""
}
func (x *SaveRequest) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
func (x *SaveRequest) GetTimestamp() int64 {
if x != nil {
return x.Timestamp
}
return 0
}
func (x *SaveRequest) GetTags() []string {
if x != nil {
return x.Tags
}
return nil
}
func (x *SaveRequest) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *SaveRequest) GetImage() string {
if x != nil {
return x.Image
}
return ""
}
type SaveResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *SaveResponse) Reset() {
*x = SaveResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SaveResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SaveResponse) ProtoMessage() {}
func (x *SaveResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SaveResponse.ProtoReflect.Descriptor instead.
func (*SaveResponse) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{4}
}
func (x *SaveResponse) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type DeleteRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *DeleteRequest) Reset() {
*x = DeleteRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteRequest) ProtoMessage() {}
func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead.
func (*DeleteRequest) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{5}
}
func (x *DeleteRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type DeleteResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DeleteResponse) Reset() {
*x = DeleteResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteResponse) ProtoMessage() {}
func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead.
func (*DeleteResponse) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{6}
}
var File_proto_posts_proto protoreflect.FileDescriptor
var file_proto_posts_proto_rawDesc = []byte{
0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x22, 0xc4, 0x02, 0x0a, 0x04, 0x50,
0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75,
0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x18, 0x0a,
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01,
0x28, 0x03, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28,
0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x73, 0x74,
0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14,
0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69,
0x6d, 0x61, 0x67, 0x65, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0x72, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x32, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f,
0x73, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x22, 0xa4, 0x02, 0x0a, 0x0b, 0x53, 0x61,
0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74,
0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73,
0x6c, 0x75, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a,
0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x74,
0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12,
0x3c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a,
0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d,
0x61, 0x67, 0x65, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x22, 0x1e, 0x0a, 0x0c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x32, 0xa9, 0x01, 0x0a, 0x05, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x34, 0x0a,
0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x51,
0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x6f,
0x73, 0x74, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x61, 0x76, 0x65, 0x12, 0x12, 0x2e, 0x70, 0x6f,
0x73, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x69,
0x63, 0x72, 0x6f, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x70, 0x6f, 0x73,
0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proto_posts_proto_rawDescOnce sync.Once
file_proto_posts_proto_rawDescData = file_proto_posts_proto_rawDesc
)
func file_proto_posts_proto_rawDescGZIP() []byte {
file_proto_posts_proto_rawDescOnce.Do(func() {
file_proto_posts_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_posts_proto_rawDescData)
})
return file_proto_posts_proto_rawDescData
}
var file_proto_posts_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_proto_posts_proto_goTypes = []interface{}{
(*Post)(nil), // 0: posts.Post
(*QueryRequest)(nil), // 1: posts.QueryRequest
(*QueryResponse)(nil), // 2: posts.QueryResponse
(*SaveRequest)(nil), // 3: posts.SaveRequest
(*SaveResponse)(nil), // 4: posts.SaveResponse
(*DeleteRequest)(nil), // 5: posts.DeleteRequest
(*DeleteResponse)(nil), // 6: posts.DeleteResponse
nil, // 7: posts.Post.MetadataEntry
nil, // 8: posts.SaveRequest.MetadataEntry
}
var file_proto_posts_proto_depIdxs = []int32{
7, // 0: posts.Post.metadata:type_name -> posts.Post.MetadataEntry
0, // 1: posts.QueryResponse.posts:type_name -> posts.Post
8, // 2: posts.SaveRequest.metadata:type_name -> posts.SaveRequest.MetadataEntry
1, // 3: posts.Posts.Query:input_type -> posts.QueryRequest
3, // 4: posts.Posts.Save:input_type -> posts.SaveRequest
5, // 5: posts.Posts.Delete:input_type -> posts.DeleteRequest
2, // 6: posts.Posts.Query:output_type -> posts.QueryResponse
4, // 7: posts.Posts.Save:output_type -> posts.SaveResponse
6, // 8: posts.Posts.Delete:output_type -> posts.DeleteResponse
6, // [6:9] is the sub-list for method output_type
3, // [3:6] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proto_posts_proto_init() }
func file_proto_posts_proto_init() {
if File_proto_posts_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proto_posts_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Post); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QueryRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QueryResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SaveRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SaveResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_posts_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_posts_proto_goTypes,
DependencyIndexes: file_proto_posts_proto_depIdxs,
MessageInfos: file_proto_posts_proto_msgTypes,
}.Build()
File_proto_posts_proto = out.File
file_proto_posts_proto_rawDesc = nil
file_proto_posts_proto_goTypes = nil
file_proto_posts_proto_depIdxs = nil
}

View File

@@ -0,0 +1,129 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/posts.proto
package posts
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/micro/v3/service/api"
client "github.com/micro/micro/v3/service/client"
server "github.com/micro/micro/v3/service/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Posts service
func NewPostsEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Posts service
type PostsService interface {
// Query currently only supports read by slug or timestamp, no listing.
Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error)
Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error)
Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error)
}
type postsService struct {
c client.Client
name string
}
func NewPostsService(name string, c client.Client) PostsService {
return &postsService{
c: c,
name: name,
}
}
func (c *postsService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Query", in)
out := new(QueryResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *postsService) Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Save", in)
out := new(SaveResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *postsService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Delete", in)
out := new(DeleteResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Posts service
type PostsHandler interface {
// Query currently only supports read by slug or timestamp, no listing.
Query(context.Context, *QueryRequest, *QueryResponse) error
Save(context.Context, *SaveRequest, *SaveResponse) error
Delete(context.Context, *DeleteRequest, *DeleteResponse) error
}
func RegisterPostsHandler(s server.Server, hdlr PostsHandler, opts ...server.HandlerOption) error {
type posts interface {
Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error
Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error
Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error
}
type Posts struct {
posts
}
h := &postsHandler{hdlr}
return s.Handle(s.NewHandler(&Posts{h}, opts...))
}
type postsHandler struct {
PostsHandler
}
func (h *postsHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error {
return h.PostsHandler.Query(ctx, in, out)
}
func (h *postsHandler) Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error {
return h.PostsHandler.Save(ctx, in, out)
}
func (h *postsHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error {
return h.PostsHandler.Delete(ctx, in, out)
}

212
posts/handler/posts.go Normal file
View File

@@ -0,0 +1,212 @@
package handler
import (
"context"
"time"
"github.com/micro/micro/v3/service/errors"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/micro/v3/service/store"
"github.com/micro/dev/model"
"github.com/gosimple/slug"
proto "github.com/micro/services/posts/proto"
tags "github.com/micro/services/tags/proto"
)
const (
tagType = "post-tag"
)
type Posts struct {
Tags tags.TagsService
db model.Model
}
func NewPosts(tagsService tags.TagsService) *Posts {
createdIndex := model.ByEquality("created")
createdIndex.Order.Type = model.OrderTypeDesc
return &Posts{
Tags: tagsService,
db: model.New(
store.DefaultStore,
"posts",
model.Indexes(model.ByEquality("slug"), createdIndex),
&model.ModelOptions{
Debug: false,
},
),
}
}
func (p *Posts) Save(ctx context.Context, req *proto.SaveRequest, rsp *proto.SaveResponse) error {
if len(req.Id) == 0 {
return errors.BadRequest("proto.save.input-check", "Id is missing")
}
// read by post
posts := []*proto.Post{}
q := model.Equals("id", req.Id)
q.Order.Type = model.OrderTypeUnordered
err := p.db.List(q, &posts)
if err != nil {
return errors.InternalServerError("proto.save.store-id-read", "Failed to read post by id: %v", err.Error())
}
postSlug := slug.Make(req.Title)
// If no existing record is found, create a new one
if len(posts) == 0 {
post := &proto.Post{
Id: req.Id,
Title: req.Title,
Content: req.Content,
Tags: req.Tags,
Slug: postSlug,
Created: time.Now().Unix(),
Metadata: req.Metadata,
Image: req.Image,
}
err := p.savePost(ctx, nil, post)
if err != nil {
return errors.InternalServerError("proto.save.post-save", "Failed to save new post: %v", err.Error())
}
return nil
}
oldPost := posts[0]
post := &proto.Post{
Id: req.Id,
Title: oldPost.Title,
Content: oldPost.Content,
Slug: oldPost.Slug,
Tags: oldPost.Tags,
Created: oldPost.Created,
Updated: time.Now().Unix(),
Metadata: req.Metadata,
Image: req.Image,
}
if len(req.Title) > 0 {
post.Title = req.Title
post.Slug = slug.Make(post.Title)
}
if len(req.Slug) > 0 {
post.Slug = req.Slug
}
if len(req.Content) > 0 {
post.Content = req.Content
}
if len(req.Tags) > 0 {
// Handle the special case of deletion
if len(req.Tags) == 0 && req.Tags[0] == "" {
post.Tags = []string{}
} else {
post.Tags = req.Tags
}
}
postsWithThisSlug := []*proto.Post{}
err = p.db.List(model.Equals("slug", postSlug), &postsWithThisSlug)
if err != nil {
return errors.InternalServerError("proto.save.store-read", "Failed to read post by slug: %v", err.Error())
}
if len(postsWithThisSlug) > 0 {
if oldPost.Id != postsWithThisSlug[0].Id {
return errors.BadRequest("proto.save.slug-check", "An other post with this slug already exists")
}
}
return p.savePost(ctx, oldPost, post)
}
func (p *Posts) savePost(ctx context.Context, oldPost, post *proto.Post) error {
err := p.db.Save(post)
if err != nil {
return err
}
if oldPost == nil {
for _, tagName := range post.Tags {
_, err := p.Tags.Add(ctx, &tags.AddRequest{
ResourceID: post.Id,
Type: tagType,
Title: tagName,
})
if err != nil {
return err
}
}
return nil
}
return p.diffTags(ctx, post.Id, oldPost.Tags, post.Tags)
}
func (p *Posts) diffTags(ctx context.Context, parentID string, oldTagNames, newTagNames []string) error {
oldTags := map[string]struct{}{}
for _, v := range oldTagNames {
oldTags[v] = struct{}{}
}
newTags := map[string]struct{}{}
for _, v := range newTagNames {
newTags[v] = struct{}{}
}
for i := range oldTags {
_, stillThere := newTags[i]
if !stillThere {
_, err := p.Tags.Remove(ctx, &tags.RemoveRequest{
ResourceID: parentID,
Type: tagType,
Title: i,
})
if err != nil {
logger.Errorf("Error decreasing count for tag '%v' with type '%v' for parent '%v'", i, tagType, parentID)
}
}
}
for i := range newTags {
_, newlyAdded := oldTags[i]
if newlyAdded {
_, err := p.Tags.Add(ctx, &tags.AddRequest{
ResourceID: parentID,
Type: tagType,
Title: i,
})
if err != nil {
logger.Errorf("Error increasing count for tag '%v' with type '%v' for parent '%v': %v", i, tagType, parentID, err)
}
}
}
return nil
}
func (p *Posts) Query(ctx context.Context, req *proto.QueryRequest, rsp *proto.QueryResponse) error {
var q model.Query
if len(req.Slug) > 0 {
logger.Infof("Reading post by slug: %v", req.Slug)
q = model.Equals("slug", req.Slug)
} else if len(req.Id) > 0 {
logger.Infof("Reading post by id: %v", req.Id)
q = model.Equals("id", req.Id)
q.Order.Type = model.OrderTypeUnordered
} else {
q = model.Equals("created", nil)
q.Order.Type = model.OrderTypeDesc
var limit uint
limit = 20
if req.Limit > 0 {
limit = uint(req.Limit)
}
q.Limit = int64(limit)
q.Offset = req.Offset
logger.Infof("Listing posts, offset: %v, limit: %v", req.Offset, limit)
}
return p.db.List(q, &rsp.Posts)
}
func (p *Posts) Delete(ctx context.Context, req *proto.DeleteRequest, rsp *proto.DeleteResponse) error {
logger.Info("Received Post.Delete request")
q := model.Equals("id", req.Id)
q.Order.Type = model.OrderTypeUnordered
return p.db.Delete(q)
}

25
posts/main.go Normal file
View File

@@ -0,0 +1,25 @@
package main
import (
"github.com/micro/micro/v3/service"
"github.com/micro/micro/v3/service/logger"
"github.com/micro/services/posts/handler"
tags "github.com/micro/services/tags/proto"
)
func main() {
// Create the service
srv := service.New(
service.Name("posts"),
)
// Register Handler
srv.Handle(handler.NewPosts(
tags.NewTagsService("tags", srv.Client()),
))
// Run service
if err := srv.Run(); err != nil {
logger.Fatal(err)
}
}

1
posts/micro.mu Normal file
View File

@@ -0,0 +1 @@
service posts

736
posts/proto/posts.pb.go Normal file
View File

@@ -0,0 +1,736 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.6.1
// source: proto/posts.proto
package posts
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type Post struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Slug string `protobuf:"bytes,3,opt,name=slug,proto3" json:"slug,omitempty"`
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
Created int64 `protobuf:"varint,5,opt,name=created,proto3" json:"created,omitempty"`
Updated int64 `protobuf:"varint,6,opt,name=updated,proto3" json:"updated,omitempty"`
Author string `protobuf:"bytes,7,opt,name=author,proto3" json:"author,omitempty"`
Tags []string `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"`
Metadata map[string]string `protobuf:"bytes,9,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Image string `protobuf:"bytes,19,opt,name=image,proto3" json:"image,omitempty"`
}
func (x *Post) Reset() {
*x = Post{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Post) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Post) ProtoMessage() {}
func (x *Post) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Post.ProtoReflect.Descriptor instead.
func (*Post) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{0}
}
func (x *Post) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *Post) GetTitle() string {
if x != nil {
return x.Title
}
return ""
}
func (x *Post) GetSlug() string {
if x != nil {
return x.Slug
}
return ""
}
func (x *Post) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
func (x *Post) GetCreated() int64 {
if x != nil {
return x.Created
}
return 0
}
func (x *Post) GetUpdated() int64 {
if x != nil {
return x.Updated
}
return 0
}
func (x *Post) GetAuthor() string {
if x != nil {
return x.Author
}
return ""
}
func (x *Post) GetTags() []string {
if x != nil {
return x.Tags
}
return nil
}
func (x *Post) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *Post) GetImage() string {
if x != nil {
return x.Image
}
return ""
}
// Query posts. Acts as a listing when no id or slug provided.
// Gets a single post by id or slug if any of them provided.
type QueryRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"`
Tag string `protobuf:"bytes,3,opt,name=tag,proto3" json:"tag,omitempty"`
Offset int64 `protobuf:"varint,4,opt,name=offset,proto3" json:"offset,omitempty"`
Limit int64 `protobuf:"varint,5,opt,name=limit,proto3" json:"limit,omitempty"`
}
func (x *QueryRequest) Reset() {
*x = QueryRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QueryRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QueryRequest) ProtoMessage() {}
func (x *QueryRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QueryRequest.ProtoReflect.Descriptor instead.
func (*QueryRequest) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{1}
}
func (x *QueryRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *QueryRequest) GetSlug() string {
if x != nil {
return x.Slug
}
return ""
}
func (x *QueryRequest) GetTag() string {
if x != nil {
return x.Tag
}
return ""
}
func (x *QueryRequest) GetOffset() int64 {
if x != nil {
return x.Offset
}
return 0
}
func (x *QueryRequest) GetLimit() int64 {
if x != nil {
return x.Limit
}
return 0
}
type QueryResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Posts []*Post `protobuf:"bytes,1,rep,name=posts,proto3" json:"posts,omitempty"`
}
func (x *QueryResponse) Reset() {
*x = QueryResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *QueryResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*QueryResponse) ProtoMessage() {}
func (x *QueryResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use QueryResponse.ProtoReflect.Descriptor instead.
func (*QueryResponse) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{2}
}
func (x *QueryResponse) GetPosts() []*Post {
if x != nil {
return x.Posts
}
return nil
}
type SaveRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"`
Slug string `protobuf:"bytes,3,opt,name=slug,proto3" json:"slug,omitempty"`
Content string `protobuf:"bytes,4,opt,name=content,proto3" json:"content,omitempty"`
Timestamp int64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
// When updating a post and wanting to delete all tags,
// send a list of tags with only one member being an empty string [""]
Tags []string `protobuf:"bytes,6,rep,name=tags,proto3" json:"tags,omitempty"`
Metadata map[string]string `protobuf:"bytes,7,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Image string `protobuf:"bytes,8,opt,name=image,proto3" json:"image,omitempty"`
}
func (x *SaveRequest) Reset() {
*x = SaveRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SaveRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SaveRequest) ProtoMessage() {}
func (x *SaveRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SaveRequest.ProtoReflect.Descriptor instead.
func (*SaveRequest) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{3}
}
func (x *SaveRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *SaveRequest) GetTitle() string {
if x != nil {
return x.Title
}
return ""
}
func (x *SaveRequest) GetSlug() string {
if x != nil {
return x.Slug
}
return ""
}
func (x *SaveRequest) GetContent() string {
if x != nil {
return x.Content
}
return ""
}
func (x *SaveRequest) GetTimestamp() int64 {
if x != nil {
return x.Timestamp
}
return 0
}
func (x *SaveRequest) GetTags() []string {
if x != nil {
return x.Tags
}
return nil
}
func (x *SaveRequest) GetMetadata() map[string]string {
if x != nil {
return x.Metadata
}
return nil
}
func (x *SaveRequest) GetImage() string {
if x != nil {
return x.Image
}
return ""
}
type SaveResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *SaveResponse) Reset() {
*x = SaveResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *SaveResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SaveResponse) ProtoMessage() {}
func (x *SaveResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SaveResponse.ProtoReflect.Descriptor instead.
func (*SaveResponse) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{4}
}
func (x *SaveResponse) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type DeleteRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *DeleteRequest) Reset() {
*x = DeleteRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteRequest) ProtoMessage() {}
func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead.
func (*DeleteRequest) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{5}
}
func (x *DeleteRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
type DeleteResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DeleteResponse) Reset() {
*x = DeleteResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_proto_posts_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteResponse) ProtoMessage() {}
func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_posts_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead.
func (*DeleteResponse) Descriptor() ([]byte, []int) {
return file_proto_posts_proto_rawDescGZIP(), []int{6}
}
var File_proto_posts_proto protoreflect.FileDescriptor
var file_proto_posts_proto_rawDesc = []byte{
0x0a, 0x11, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x22, 0xc4, 0x02, 0x0a, 0x04, 0x50,
0x6f, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75,
0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x18, 0x0a,
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74,
0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01,
0x28, 0x03, 0x52, 0x07, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x61,
0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28,
0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x6f, 0x73, 0x74,
0x73, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14,
0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69,
0x6d, 0x61, 0x67, 0x65, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0x72, 0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x61, 0x67, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x74, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12,
0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05,
0x6c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x32, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x18,
0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x50, 0x6f,
0x73, 0x74, 0x52, 0x05, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x22, 0xa4, 0x02, 0x0a, 0x0b, 0x53, 0x61,
0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74,
0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73,
0x6c, 0x75, 0x67, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x1c, 0x0a,
0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x74,
0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12,
0x3c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a,
0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d,
0x61, 0x67, 0x65, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x22, 0x1e, 0x0a, 0x0c, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x22, 0x1f, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x32, 0xa9, 0x01, 0x0a, 0x05, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x12, 0x34, 0x0a,
0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x51,
0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x6f,
0x73, 0x74, 0x73, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x04, 0x53, 0x61, 0x76, 0x65, 0x12, 0x12, 0x2e, 0x70, 0x6f,
0x73, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x13, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x12, 0x14, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x2e, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42,
0x0d, 0x5a, 0x0b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x70, 0x6f, 0x73, 0x74, 0x73, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_proto_posts_proto_rawDescOnce sync.Once
file_proto_posts_proto_rawDescData = file_proto_posts_proto_rawDesc
)
func file_proto_posts_proto_rawDescGZIP() []byte {
file_proto_posts_proto_rawDescOnce.Do(func() {
file_proto_posts_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_posts_proto_rawDescData)
})
return file_proto_posts_proto_rawDescData
}
var file_proto_posts_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_proto_posts_proto_goTypes = []interface{}{
(*Post)(nil), // 0: posts.Post
(*QueryRequest)(nil), // 1: posts.QueryRequest
(*QueryResponse)(nil), // 2: posts.QueryResponse
(*SaveRequest)(nil), // 3: posts.SaveRequest
(*SaveResponse)(nil), // 4: posts.SaveResponse
(*DeleteRequest)(nil), // 5: posts.DeleteRequest
(*DeleteResponse)(nil), // 6: posts.DeleteResponse
nil, // 7: posts.Post.MetadataEntry
nil, // 8: posts.SaveRequest.MetadataEntry
}
var file_proto_posts_proto_depIdxs = []int32{
7, // 0: posts.Post.metadata:type_name -> posts.Post.MetadataEntry
0, // 1: posts.QueryResponse.posts:type_name -> posts.Post
8, // 2: posts.SaveRequest.metadata:type_name -> posts.SaveRequest.MetadataEntry
1, // 3: posts.Posts.Query:input_type -> posts.QueryRequest
3, // 4: posts.Posts.Save:input_type -> posts.SaveRequest
5, // 5: posts.Posts.Delete:input_type -> posts.DeleteRequest
2, // 6: posts.Posts.Query:output_type -> posts.QueryResponse
4, // 7: posts.Posts.Save:output_type -> posts.SaveResponse
6, // 8: posts.Posts.Delete:output_type -> posts.DeleteResponse
6, // [6:9] is the sub-list for method output_type
3, // [3:6] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proto_posts_proto_init() }
func file_proto_posts_proto_init() {
if File_proto_posts_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_proto_posts_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Post); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QueryRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*QueryResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SaveRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*SaveResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_proto_posts_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_posts_proto_rawDesc,
NumEnums: 0,
NumMessages: 9,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_posts_proto_goTypes,
DependencyIndexes: file_proto_posts_proto_depIdxs,
MessageInfos: file_proto_posts_proto_msgTypes,
}.Build()
File_proto_posts_proto = out.File
file_proto_posts_proto_rawDesc = nil
file_proto_posts_proto_goTypes = nil
file_proto_posts_proto_depIdxs = nil
}

View File

@@ -0,0 +1,129 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: proto/posts.proto
package posts
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
math "math"
)
import (
context "context"
api "github.com/micro/micro/v3/service/api"
client "github.com/micro/micro/v3/service/client"
server "github.com/micro/micro/v3/service/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Posts service
func NewPostsEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Posts service
type PostsService interface {
// Query currently only supports read by slug or timestamp, no listing.
Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error)
Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error)
Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error)
}
type postsService struct {
c client.Client
name string
}
func NewPostsService(name string, c client.Client) PostsService {
return &postsService{
c: c,
name: name,
}
}
func (c *postsService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Query", in)
out := new(QueryResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *postsService) Save(ctx context.Context, in *SaveRequest, opts ...client.CallOption) (*SaveResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Save", in)
out := new(SaveResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *postsService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) {
req := c.c.NewRequest(c.name, "Posts.Delete", in)
out := new(DeleteResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Posts service
type PostsHandler interface {
// Query currently only supports read by slug or timestamp, no listing.
Query(context.Context, *QueryRequest, *QueryResponse) error
Save(context.Context, *SaveRequest, *SaveResponse) error
Delete(context.Context, *DeleteRequest, *DeleteResponse) error
}
func RegisterPostsHandler(s server.Server, hdlr PostsHandler, opts ...server.HandlerOption) error {
type posts interface {
Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error
Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error
Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error
}
type Posts struct {
posts
}
h := &postsHandler{hdlr}
return s.Handle(s.NewHandler(&Posts{h}, opts...))
}
type postsHandler struct {
PostsHandler
}
func (h *postsHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error {
return h.PostsHandler.Query(ctx, in, out)
}
func (h *postsHandler) Save(ctx context.Context, in *SaveRequest, out *SaveResponse) error {
return h.PostsHandler.Save(ctx, in, out)
}
func (h *postsHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error {
return h.PostsHandler.Delete(ctx, in, out)
}

62
posts/proto/posts.proto Normal file
View File

@@ -0,0 +1,62 @@
syntax = "proto3";
package posts;
option go_package = "proto;posts";
service Posts {
// Query currently only supports read by slug or timestamp, no listing.
rpc Query(QueryRequest) returns (QueryResponse) {}
rpc Save(SaveRequest) returns (SaveResponse) {}
rpc Delete(DeleteRequest) returns (DeleteResponse) {}
}
message Post {
string id = 1;
string title = 2;
string slug = 3;
string content = 4;
int64 created = 5;
int64 updated = 6;
string author = 7;
repeated string tags = 8;
map<string,string> metadata = 9;
string image = 19;
}
// Query posts. Acts as a listing when no id or slug provided.
// Gets a single post by id or slug if any of them provided.
message QueryRequest {
string id = 1;
string slug = 2;
string tag = 3;
int64 offset = 4;
int64 limit = 5;
}
message QueryResponse {
repeated Post posts = 1;
}
message SaveRequest {
string id = 1;
string title = 2;
string slug = 3;
string content = 4;
int64 timestamp = 5;
// When updating a post and wanting to delete all tags,
// send a list of tags with only one member being an empty string [""]
repeated string tags = 6;
map<string,string> metadata = 7;
string image = 8;
}
message SaveResponse {
string id = 1;
}
message DeleteRequest {
string id = 1;
}
message DeleteResponse {}