Skip to content

Latest commit

 

History

History
651 lines (533 loc) · 27.1 KB

reference.md

File metadata and controls

651 lines (533 loc) · 27.1 KB

Rellaf 参考手册

Model(反射类)

头文件: model.h

说明:
ModelRellaf的核心,所有工作都围绕在Model反射类的特性来实现。

数据类型

rellaf反射类定义的类型如下:

rellaf类型 c++类型 定义宏后缀
no(表示未定义) N/A N/A
CHAR char char
INT16 int16_t int16
INT int int
INT64 int64_t int64
UINT16 uint16_t uint16
UINT32 uint32_t uint32
UINT64 uint64_t uint64
BOOL bool bool
FLOAT float float
DOUBLE double double
STR std::string str
OBJECT rellaf::Object object
LIST rellaf::List list
为什么是int, 而不是int32? 因为int这个类型广泛通用,早已得到普遍接受。

Model基类

说明:
Modelrellaf反射类的虚基类,用来定义通用接口。

方法列表:

方法名 说明 返回值 参数
rellaf_type 返回Model类型 ModelType N/A
rellaf_name 返回Model名字 std::string N/A
<T>tag 给当前Model增加一个字符串类型tag T&(当前Model的引用) std::string
rellaf_tags 返回Model的tag集合 std::deque<std::string> N/A
create 构造一个新的Model Model* N/A
clone 复制当前对象 Model* N/A
assign 对象赋值 void N/A
clear 清空 void N/A
debug_str 返回debug字符串 std::string N/A

Plain

说明:
继承ModelPlainrellaf反射类对于C++普通类型的包装,模板类,需要指定包装类型,支持能够调用std::string的类型。

Plain在构造的时候,会自动检测包装的类型,并设置关联ModelType,从而rellaf_type能够将其返回。

方法列表:

方法名 说明 返回值 参数
<T>构造函数 默认构造,其他Plain对象或具体类型的赋值构造,复制构造和相应的移动构造 N/A Plain<T>
Model基类方法 Model Model Model
value 取值 当前包装类型 N/A
set 赋值 void 当前包装类型
set_parse 从字符串parse成当前类型的值 void std::string
equal_parse 从字符串parse成当前类型的值, 并做等值比较 bool std::string
str 把当前类型的值转换成字符串表示 std::string N/A

例子:

Plain<int> intval = 233;
intval.str();               // "233"
intval.value();             // 233
intval.set(333);               
intval.value();             // 333
intval.set_parse("555");               
intval.value();             // 555
if (intval.equal_parse("555")) {
    // true
}

List

说明:
继承Model,表示列表。加入到ListModel对调用clone方法进行对象复制,内部会维护这些对象的生命周期,无需用户手动释放内存。

目前使用std::deque实现。

方法列表:

方法名 说明 返回值 参数
<T>构造函数 默认构造,赋值构造,复制构造和相应的移动构造 N/A Plain<T>
Model基类方法 Model Model Model
size 长度 size_t N/A
empty 是否空 bool N/A
push_front 头部插入 void Model*
push_back 尾部插入 void Model*
<T>push_front 头部插入 void const T&(Model子类)
<T>push_back 尾部插入 void const T&(Model子类)
pop_front 头部删除 void N/A
pop_back 尾部删除 void N/A
<T>front 头部成员 T* N/A
<T>back 尾部成员 T* N/A
<T>at 指定索引成员 T* size_t 索引值
operator[] 指定索引成员 Model* size_t 索引值
set 设置指定索引成员 void Model*
begin 起始迭代器 std::deque<Model*>::const_iterator N/A
end 结束迭代器 std::deque<Model*>::const_iterator N/A

例子:

List list;
size_t size = list.size();      // 返回 0
bool is_empty = list.empty();   // 返回 true

// 插入成员,会进行内存复制,生命周期由Model管理。
Plain<int> item = 222;
list.push_front(&item);
list.push_back(&item);
size = list.size();             // 返回 2
is_empty = list.empty();        // 返回 false

// 索引数组成员,注意返回的是 Model*, 转换成具体类型即可
Plain<int>* ptr = list.front<Plain<int>>();
ptr = list.back<Plain<int>>();
ptr = (Plain<int>*)list[0];
ptr = (Plain<int>*)list[1];

// 遍历
for (Model* item : list) {  // 支持C++11 for循环语法
    // do something
}
for (auto i = list.begin(); i != list.end(); ++i) {
    // do something
}

// 修改
Plain<int> item_to_mod = 222;
list.set(0, &item_to_mod);
list.set(1, &item_to_mod);

// 弹出
list.pop_front();
list.pop_back();

// 清空
list.clear();

Object

说明:
继承Model,表示对象类型。加入到ObjectModel对调用clone方法进行对象复制,内部会维护这些对象的生命周期,无需用户手动释放内存。

Objectrellaf的"特色"类型,需要自定义一个类型,然后继承Object类,然后配合宏来使用。例如:

class User : public Object {
rellaf_model_dcl(User);
}
rellaf_model_def(User);

相关宏列表:

宏名 说明 参数
rellaf_model_dcl 申明Object对象 自定义类名
rellaf_model_def 定义Object对象 自定义类名
rellaf_model_def_char 定义char成员 字段名, 默认值
rellaf_model_def_int16 定义int16成员 字段名, 默认值
rellaf_model_def_int 定义int成员 字段名, 默认值
rellaf_model_def_int64 定义int64成员 字段名, 默认值
rellaf_model_def_uint16 定义uint16成员 字段名, 默认值
rellaf_model_def_uint32 定义uint32成员 字段名, 默认值
rellaf_model_def_uint64 定义uint64成员 字段名, 默认值
rellaf_model_def_bool 定义bool成员 字段名, 默认值
rellaf_model_def_float 定义float成员 字段名, 默认值
rellaf_model_def_double 定义double成员 字段名, 默认值
rellaf_model_def_str 定义str成员 字段名, 默认值
rellaf_model_def_object 定义Object成员 Object类名
rellaf_model_def_list 定义List成员 List类名

方法列表:

方法名 说明 返回值 参数
<T>构造函数 默认构造,赋值构造,复制构造和相应的移动构造 N/A Plain<T>
Model基类方法 Model Model Model
field 字段取值 void 具体类型的字段值
set_field 设置字段值 具体类型的字段值 N/A
field_default 获得字段默认值 具体类型的字段值 N/A
is_plain_member 是否是plain类型成员 bool std::string 字段名
set_plain 设置普通字段 void std::string 字段名; std::string 字符串表示的字段值
<T>get_plain 获得普通字段 Plain<T>*, 不存在返回nullptr std::string 字段名
get_plains 获得普通字段集合 std::map<std::string, Model*>& N/A
is_object_member 是否是对象字段 bool std::string 字段名
get_object 获得对象字段 Object* std::string 字段名
get_objects 获得对象字段集合 std::map<std::string, Object*>& N/A
is_list_member 是否是数组字段 bool std::string 字段名
get_list 获得数组字段 List& std::string 字段名
get_lists 获得数组字段集合 std::map<std::string, List>& N/A

例子: 定义

// 子对象
class SubObject : public Object {
rellaf_model_dcl(SubObject)
rellaf_model_def_uint16(port, 18765);
};
rellaf_model_def(SubObject);

// 父对象
class Obj : public Object {
rellaf_model_dcl(Obj)
rellaf_model_def_int(id, -111);
rellaf_model_def_str(name, "aaa");

// 定义对象,字段名,类型名(必须是Model类)
rellaf_model_def_object(sub, SubObject);

// 定义数组,字段名,类型名(必须是Model类)
rellaf_model_def_list(list, Plain<int>); 
};
rellaf_model_def(Obj);

操作

Obj object;
// 常规操作
object.set_id(123);
object.set_name("fankux");

// 初始情况下是nullptr
SubObject* ptr = object.sub();    

// 赋值一个对象, 会进行内存复制,生命周期由Model管理。
SubObject sub;
object.set_sub(&sub);

// 给对象成员的成员赋值(注意,对象成员方法返回的是指针)
object.sub()->set_port(8121);
// 通过字段名字符串索引, 若不存在则返回nullptr
ptr = object->get_object("sub");
ptr->set_port(8121);

// 取值, 返回 8121
uint16_t port = object.sub()->port();
port = object.sub()->get_uint16("port");

Void

说明:
继承Model,表示无类型

方法列表:

方法名 说明 返回值 参数
rellaf_type 返回no类型 ModelType::e().no N/A
create 构造一个新的Model Model* N/A
clone 复制当前对象 Model* N/A

Enum

头文件: enum.h

说明:
C/C++枚举(enum)能力很有限,只是一个数字,没有从字符串获得枚举的能力,也不能判断一个枚举是否存在。 Rellaf实现了灵活的枚举类,使用同样非常简单。与Object类似,配合相关的宏使用。

class DemoEnum : public Enum {
rellaf_enum_dcl(DemoEnum);

//  按照 code(int),name(std::string) 定义,都保证唯一。
rellaf_enum_item_def(0, A);
rellaf_enum_item_def(1, B);
};
rellaf_enum_def(DemoEnum);

相关宏列表:

宏名 说明 参数
rellaf_enum_dcl 申明Enum对象 自定义类名
rellaf_enum_def 定义Enum对象 自定义类名
rellaf_enum_item_def 定义枚举成员 自定义类名
rellaf_enum_item_code_def 定义枚举成员(带静态数字编码) 自定义类名
rellaf_enum 工具宏, 等价于 Enum::e() 自定义类名

Enum的取值都是Enum::e()这种单例访问的模式,无法使用在switch case语句中,而这需要静态数字。为了支持有了rellaf_enum_item_code_def这个宏,区别与 rellaf_enum_item_def,会额外定义数字编码静态成员。如上面的DemoEnum对象,如果换成rellaf_enum_item_code_def(0, A),则会有constexpr static int DemoEnum::A_code=0成员。

如果是C++17以上,这样就已经足够了。但是由于C++11,14,对于静态成员,一定要在类外再定义一次,然后才能使用静态数字编码如下:

constexpr int DemoEnum::A_code;

枚举成员类型是 struct EnumItem成员列表:

成员名 说明 类型
code 编码 int
name 名字 std::string

EnumItem方法列表:

方法名 说明 返回值 参数
available 是否有效 bool N/A
operator== 判断等,根据code bool EnumItem
operator!= 判断不等,根据code bool EnumItem
operator< 判断大小,根据code bool EnumItem

统一使用 Enum::e() 或 rellaf_enum(Enum) 单例访问枚举类方法。

Enum方法列表:

方法名 说明 返回值 参数
names 枚举名字合集 std::map<std::string, int>& N/A
codes 枚举编码合集 std::map<int, std::string>& N/A
get 获得枚举值 EnumItem, 如果不存在EnumItem.available() == false 有两个重载: int, 根据code查找; std::string, 根据name查找
exist 是否存在枚举值 bool 有两个重载: int, 根据code查找; std::string, 根据name查找

例子:
使用上文定义的DemoEnum

// 枚举都是单例类,通过单例方法或者 rellaf_enum宏 访问
std::string name = DemoEnum::e().A.name;                    // 返回 "A"
int code = rellaf_enum(DemoEnum).B.code;                    // 返回 1

// 静态数字编码,可用于switch case (仅C++17以上)
code = DemoEnum::A_code;                                    // 返回 1
code = DemoEnum::B_code;                                    // 返回 2
code = DemoEnum::C_code;                                    // 返回 3

// 比较
if (DemoEnum::e().B != DemoEnum::e().C) {
    // B not equal C
}

// 判断是否存在
DemoEnum::e().exist(2);                                     // 返回 true
DemoEnum::e().exist("D");                                   // 返回 false

// 取值
EnumItem name = DemoEnum::e().get("B");
if (name.available()) {
    // exist, do something
}
EnumItem code  = DemoEnum::e().get(1);
if (code.available()) {
    // exist, do something
}

// 获得取值范围
const std::map<std::string, int>& names = DemoEnum::e().names();
const std::map<int, std::string>& codes = DemoEnum::e().codes();

扩展部分

Json

头文件: json_to_model.h

显然,这是一个提供Model对象和Json互相转换的库。当前版本使用依赖Jsoncpp实现(rapidjson性能更佳, 待调研)。

目前包含2个API:
bool model_to_json(const Model* model, std::string& json_str, bool is_format = false);
bool json_to_model(const std::string& json_str, Model* model);

根据字面意思,就是字符串表示的Json与Model类型的相互转换,is_format表示是否换行缩进。注意几点:

  • model_to_json总是返回true,Object或者List成员如果是nullptr,则输出Json的null value。
  • json_to_model如果输入字符串parse json失败,返回false,否则返回true。
  • Model定义的结构可能与输入的Json不一样,结构不一致的部分会跳过转换。
  • Json object为null value的成员,不会进行转换。

类型对应:

rellaf类型 Jsoncpp类型
CHAR Json::Int
INT16 Json::Int
INT Json::Int
INT64 Json::Int64
UINT16 Json::UInt
UINT32 Json::UInt
UINT64 Json::UInt64
BOOL Json::booleanValue
FLOAT Json::realValue
DOUBLE Json::realValue
STR Json::stringValue

SqlBuilder

头文件: sql_builder.h

这是一个“拼SQL器”,或者说“DAO”?当然,我们不会去做过度的包装,屏蔽SQL语法而直接去做数据操作映射,对于C++界来说,这种设计“太过了”。所以参考了Java界的Mybatis的那种感觉,配置一个SQL模板,设置一系列占位符,同时生成调用方法,用户访问这个SQL,直接调用这个方法,传入对应的Model类即可。

我们来看一个简单的例子,从select语句着手。

  1. 首先,定义参数和返回值相关Model, 这个与前面介绍一致。
// 参数类
class Arg : public Object {
rellaf_model_dcl(Arg);

rellaf_model_def_str(cond, "condition");
rellaf_model_def_list(ids, Plain<int>);
};
rellaf_model_def(Arg);

// 返回值类
class Ret : public Object {
rellaf_model_dcl(Ret);

rellaf_model_def_str(a, "");
rellaf_model_def_int(b, 0);
rellaf_model_def_float(c, 0);
};
rellaf_model_def(Ret);
  1. 继承SqlBuilder,并用宏rellaf_sql_select来定义sql_builder
// 定义sql_builder
class DemoBuilder : public SqlBuilder {
rellaf_singleton(DemoBuilder);

// 会生成2个方法,签名如下:
// 这个方法会执行SQL,ret是传出结果集, arg是可变参模板函数,要求是Model子类
// int select_func(Ret& ret, Arg& ...arg);
// 这个方法不执行SQL,仅通过sql传出拼接完的结果SQL, arg是可变参模板函数,要求是Model子类
// int select_func_sql(std::string& sql, Arg& ...arg);
rellaf_sql_select(select_func, "SELECT a, b, c FROM table WHERE cond=#{cond}", Ret);

// 在定义一个生成列表的
rellaf_sql_select(select_func_ids, "SELECT a, b, c FROM table WHERE id IN (#[ids])", Ret);

};
  1. 此时,我们已经ok了,可以使用了
// 调用
Ret ret;
Arg arg;
Plain<int> id = 1;
arg.ids().push_back(id);
id = 2;
arg.ids().push_back(id);

std::string sql;
DemoBuilder::instance().select_func_sql(sql, arg);
// sql为: SELECT a, b, c FROM table WHERE cond='condition'
DemoBuilder::instance().select_func(ret, arg);
// 执行sql, ret从上述SQL在DB中执行结果返回第一行记录(如果有), 
// 取a,b,c三个字段的值, 根据类型自动转换, 然后放入ret对应的字段中。

DemoBuilder::instance().select_func_ids_sql(sql, id);
// sql为: SELECT a, b, c FROM table WHERE id IN (1, 2)
// 执行与上面类似, 略

上面介绍都是单个参数,下面来看多个参数,我们延续上面的例子,再定义一个SQL模板:

// 生成两个方法,除了方法名,其他与上面一致,因为参数是可变的。
// int select_multi(Ret& ret, Arg& ...arg);
// int select_multi_sql(std::string& sql, Arg& ...arg);
rellaf_sql_select(select_multi,
        "SELECT a, b, c FROM table WHERE cond=#{a.cond} AND id IN (#[b.ids])", Ret);

调用:

// 再定义一个参数
Arg arg2;
arg2.set_cond("condition2");

DemoBuilder::instance().select_multi_sql(sql, arg2.tag("a"), arg.tag("b"));
// sql为: SELECT a, b, c FROM table WHERE cond='condition2' AND id IN (1, 2)

为了支持多个参数,我们引入了tag概念,给Model增加一个标签,同时两个占位符分别加上了a.b.
这就是为了区分数据要从两个不同的参数中去取,同时,这种机制也不要求传入参数的顺序,根据tag对应即可。

tag方法:
T& tag(const std::string& tag_str);
Model设置一个字符串表示的标签。
对应的,也有获取tag的方法:
const std::string& rellaf_tag() const;
这两个方法都在Model基类定义。

现在我们来详细讲一下上面的占位符,分两种:单值占位符,#{placeholder}列表占位符,#[placeholder]
单值就是把变量转换为SQL的表示方式;列表是指,传入值是个List,则生成逗号分隔的SQL值。
值都会进行转义操作,目前是借助了mysql_real_escape()等价的代码实现的(基于单引号'),仅实现了utf8和gbk两种编码。
placeholder可以支持点分的形式,例如 #{a.b.c},用来处理嵌套的Model或者多个传入参数,规则如下:

占位符 Plain Object List Model.tag("a")
#{a} 值(a可以是任意字符串) 字段a的值,必须是Plain N/A Model为Plain时取其值,其他N/A
#{a.b} N/A 字段a的必须是Object,取其成员b,其必须是Plain N/A 对Model执行#{b}规则
#{a.<1>} N/A 字段a必须是List,取第1个(0开始)成员,且必须是Plain N/A N/A
#{a.<1>.b} N/A 字段a必须是List,且其成员必须是Object,取第1个成员的字段b,其必须是Plain N/A N/A
#[] N/A N/A 成员必须是Plain,把所有值按逗号分隔拼接 N/A
#[a] N/A 成员a必须是List,其成员必须是Plain,把所有值按逗号分隔拼接 N/A Model为List时执行#[]规则,其他N/A
#[a.b] N/A 成员a必须Object, 取其成员b,其必须是List,其成员必须是Plain,把所有值按逗号分隔拼接 N/A 对Model执行#[b]规则
#[a.<1>] N/A 成员a必须List,取其第1个成员,其必须是List,其成员必须是Plain,把所有值按逗号分隔拼接 N/A N/A
#[a.<1>.b] N/A 成员a必须List,取其第1个成员,其必须是Object,取其字段b,其必须是List,其成员必须是Plain,把所有值按逗号分隔拼接 N/A N/A

#{placeholder}的最后一部分必须是Plain
#[placeholder]的最后一部分必须是List

SqlBuilder相关宏和方法:

宏名 生成的接口签名
rellaf_sql_select(func, pattern, Ret) int func(Ret& ret, Arg& ...args)
int func _sql(std::string& sql, Arg& ...args)
rellaf_sql_select_list(func, pattern, Ret) int func(std::deque<Ret>& ret, Arg& ...args)
int func _sql(std::string& sql, Arg& ...args)
rellaf_sql_insert(func, pattern) int func(Arg& ...args)
int func _sql(std::string& sql, Arg& ...args)
rellaf_sql_update(func, pattern) int func(Arg& ...args)
int func _sql(std::string& sql, Arg& ...args)
rellaf_sql_delete(func, pattern) int func(Arg& ...args)
int func _sql(std::string& sql, Arg& ...args)

说明:
参数func是方法名;pattern是SQL模板;Ret是返回值类型,必须是Model子类。
rellaf_sql_select_listrellaf_sql_select区别是一个返回多行数据,放到std::deque里,一个只返回单行数据。
返回值,-1表示失败,值大于等与0对于select表示返回的行数,对于insertupdatedelete表示受影响的行数

TODO... SQL executor接口

关于if else选择器,待调研一下。

Brpc

头文件: brpc_dispatcher.h

主要功能:

  • 相同API的POST和GET类型请求可以直接映射到不同的处理函数。
  • 建立了HTTP API,proto接口签名,具体处理函数的直接关联。一行代码定义关联。
  • 包装了HTTP请求相关上下文数据,直接传递给处理函数。
  • HTTP body,request query,path variable都能自动到Model的转换。处理函数参数可指定。
  • 处理函数直接返回Model,可自动转换成Json或字符串。

HttpContext:
HTTP请求上下文数据包,包装了Brpc HTTP请求相关的原始数据。request_header, request_body, path_vars是输入请求,其中path_varsstd::map形态的路径变量方便使用, 只读。response_header, response_body 是应答数据, 可以修改, 以实现HTTP的各种响应功能。原型:

struct HttpContext {
    const HttpHeader& request_header;
    const butil::IOBuf& request_body;
    const std::map<std::string, std::string>& path_vars;
    HttpHeader& response_header;
    butil::IOBuf& response_body;
};

除了这个原始的Brpc HTTP上下文数据结构, Rellaf做的主要工作是, 把HTTP常用的方式和数据处理模型进行封装,包括几类:

查询字符串:
有HTTP API:api/{id}/to/request?a=111&b=222,其中a=111&b=222就是查询字符串, 简单来说就是k-v数据, Rellaf可以将其自动转换成Object供调用方直接使用。(HTTP允许一个k设置多个v, 这个暂时不支持)

路径变量:
使用{变量名}的方式定义, 有HTTP API:api/{id}/to/request?a=111&b=222,其中{id}路径变量, 假如真实请求是'http://www.xxxx.com/api/666/to/request?a=111&b=222', 那么666就是路径变量的实参, 这也是k-v数据, Rellaf同样可以将其自动转换成Object

请求Body:
目前业内常用的'套路'是请求Body用Json字符串, 借助于Rellaf的Json转换能力, 我们同样可以自动将其自动转换为Model。如果定义的是Plain类型,则会用这个字符串去解析赋值,比如Plain<std::string>可以拿到请求Body的原始字符串。

应答Body:
请求Body相反, 用户自定义处理完成后, 返回的Model将自动转换为Json字符串(如果是Plain就是对应的普通字符串),然后放到HTTP的应答Body中。

我们先通过一个例子来看一下最简单的用法,假设场景:
使用与上面一样的rest风格接口api/{id}/to/request,并且能够将HTTP body转换为BodyObject),请求查询参数转换为ParamsObject),路径变量转换为Vars(Model)。请求处理完成后,返回HTTP body字符串为“OK”拼接{id}的值。

  1. 定义protobuf文件,生成protobuf service接口,这个过程看brpc文档。假设我们定义的Protobuf Service是:
option cc_generic_services = true;
message DemoRequest {};
message DemoResponse {};
// DemoRequest,DemoResponse是protobuf要求的请求和应答类型,这个在这里不起作用,但是要写
service DemoService {
    rpc hi (DemoRequest) returns (DemoResponse);
}
  1. 定义一个rellaf service
class DemoServiceImpl : public BrpcService, public DemoService {
rellaf_brpc_http_dcl(DemoServiceImpl, DemoRequest, DemoResponse);
// 定义API和处理函数的映射
rellaf_brpc_http_def_post(hi, "api/{id}/to/request", hi_handler, Plain<std::string>, Params, Vars, Body);
};
rellaf_brpc_http_def(DemoServiceImpl);
  1. 定义接口处理函数
Plain<std::string> DemoServiceImpl::hi_handler(HttpContext& context, const Params& params, const Vars& vars, const Body& body) {
    ...
    // context.aaa
    // body.xxx
    // params.ooo
    ...
    return Plain<std::string>("OK" + vars.id());
}

也可以不用第3步单独定义,第2部时"一气呵成":

...
rellaf_brpc_http_def_post(hi, "api/{id}/to/request", hi_handler, Plain<std::string>, Params, Vars, Body) {
    ...
    // 约定 Context, Params, Vars, Body 实参分别为 ctx, p, v, b
    // ctx.aaa
    // b.xxx
    // p.ooo
    ...
    return Plain<std::string>("OK" + v.id()); 
}
...

当真实请求是'http://www.xxxx.com/api/666/to/request?a=111&b=222', HTTP Body为'12345', 有:

/* 伪代码 */
Params.a() == "111";        // true
Params.b() == "222";        // true
Vars.id() == "666";         // true
Body.string() == "12345";   // true
Ret.string() == "OK-666";   // true

这就完成了一个POST接口的请求处理。GET方法类似,区别在于没有请求Body。此外, 还提供其他宏可供不同的请求类型组合。

相关宏列表:

宏名 对应接口签名(说明)
rellaf_brpc_http_dcl 申明HTTP Service,参数:自定义类名,pb request,pb response
rellaf_brpc_http_def 定义HTTP Service,参数:自定义类名
rellaf_brpc_http_def_get Ret func(HttpContext& ctx, const Params& p, const Vars& v)
rellaf_brpc_http_def_get_param Ret func(HttpContext& ctx, const Params& p)
rellaf_brpc_http_def_get_pathvar Ret func(HttpContext& ctx, const Vars& v)
rellaf_brpc_http_def_post Ret func(HttpContext& ctx, const Params& p, const Vars& v, const Body& b)
rellaf_brpc_http_def_post_body Ret func(HttpContext& ctx, const Body& b)
rellaf_brpc_http_def_post_param Ret func(HttpContext& ctx, const Params& p)
rellaf_brpc_http_def_post_pathvar Ret func(HttpContext& ctx, const Vars& v)
rellaf_brpc_http_def_post_param_body Ret func(HttpContext& ctx, const Params& p, const Body& b)
rellaf_brpc_http_def_post_pathvar_body Ret func(HttpContext& ctx, const Vars& v, const Body& b)
rellaf_brpc_http_def_post_param_pathvar Ret func(HttpContext& ctx, const Params& p, const Vars& v)

更多Method支持,还有更多HTTP语义和特性的支持看需求逐步支持,欢迎提ISSUE。