Skip to content

Commit

Permalink
Merge pull request #21 from emqx/create_resource_cli
Browse files Browse the repository at this point in the history
Fix Bugs in HTTP APIs
  • Loading branch information
terry-xiaoyu committed Apr 10, 2019
2 parents cb83afd + d485e86 commit ed16002
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 55 deletions.
132 changes: 132 additions & 0 deletions docs/api_examples.md
@@ -0,0 +1,132 @@
#Rule-Engine-APIs



## ENVs

APPSECRET="5bce2ce904d5f8:Mjg2ODA3NTU0MjAzNTAzMTU1ODI3MzE5Mzg3MTU3Mjk5MjA"

## Rules

### create
```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/rules' -d \
'{"name":"test-rule","for":"message.publish","rawsql":"select * from \"t/a\"","actions":[{"name":"default:debug_action","params":{"a":1}}],"description":"test-rule"}'

{"code":0,"data":{"actions":["default:debug_action"],"description":"test-rule","enabled":true,"id":"test-rule:1554877610657488000","name":"test-rule","rawsql":"select * from \"t/a\""}}

## with a resource id in the action args
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/rules' -d \
'{"name":"test-rule","for":"message.publish","rawsql":"select * from \"t/a\"","actions":[{"name":"default:debug_action","params":{"$resource":"debug_resource_type:test-resource","a":1}}],"description":"test-rule"}'

{"code":0,"data":{"actions":["default:debug_action"],"description":"test-rule","enabled":true,"id":"test-rule:1554877819392283141","name":"test-rule","rawsql":"select * from \"t/a\""}}
```

### show
```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/rules/test-rule:1554877819392283141'

{"code":0,"data":{"actions":["default:debug_action"],"description":"test-rule","enabled":true,"id":"test-rule:1554877819392283141","name":"test-rule","rawsql":"select * from \"t/a\""}}
```

### list

```shell
$ curl -v --basic -u $APPSECRET -k http://localhost:8080/api/v3/rules

{"code":0,"data":[{"actions":["default:debug_action"],"description":"Rule for debug","enabled":true,"id":"inspect:1554792545782692586","name":"inspect","rawsql":"select * from t1"}]}
```

### delete

```shell
$ curl -XDELETE -v --basic -u $APPSECRET -k http://localhost:8080/api/v3/rules/inspect:1554792545782692586

{"code":0}
```



## Actions

### list

```shell
$ curl -v --basic -u $APPSECRET -k http://localhost:8080/api/v3/actions

{"code":0,"data":[{"app":"emqx_rule_engine","description":"Debug Action","name":"default:debug_action","params":{}},{"app":"emqx_rule_engine","description":"Republish a MQTT message","name":"default:republish_message","params":{"from":"topic","to":"topic"}}]}
```



### show

```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/actions/default:debug_action'

{"code":0,"data":{"app":"emqx_rule_engine","description":"Debug Action","name":"default:debug_action","params":{}}}
```



## Resource Types

### list

```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/resource_types'

{"code":0,"data":[{"description":"Debug resource type","name":"debug_resource_type","provider":"emqx_rule_engine"}]}
```



### show

```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/resource_types/debug_resource_type'

{"code":0,"data":{"description":"Debug resource type","name":"debug_resource_type","provider":"emqx_rule_engine"}}
```



## Resources

### create

```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/resources' -d \
'{"name":"test-resource", "type": "debug_resource_type", "config": {"a":1}, "description": "test-rule"}'

{"code":0,"data":{"attrs":"undefined","config":{"a":1},"description":"test-rule","id":"debug_resource_type:test-resource","type":"debug_resource_type"}}
```

### list

```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/resources'

{"code":0,"data":[{"attrs":"undefined","config":{"a":1},"description":"test-rule","id":"debug_resource_type:test-resource","type":"debug_resource_type"}]}
```



### show

```shell
$ curl -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/resources/debug_resource_type:test-resource'

{"code":0,"data":{"attrs":"undefined","config":{"a":1},"description":"test-rule","id":"debug_resource_type:test-resource","type":"debug_resource_type"}}
```



### delete

```shell
$ curl -XDELETE -v --basic -u $APPSECRET -k 'http://localhost:8080/api/v3/resources/debug_resource_type:test-res'

{"code":0}
```

4 changes: 2 additions & 2 deletions src/emqx_rule_actions.erl
Expand Up @@ -17,10 +17,10 @@

-include_lib("emqx/include/emqx.hrl").

-resource_type(#{name => default_resource,
-resource_type(#{name => debug_resource_type,
schema => "emqx_rule_engine",
create => on_resource_create,
description => "Default resource"
description => "Debug resource type"
}).

-rule_action(#{name => debug_action,
Expand Down
8 changes: 4 additions & 4 deletions src/emqx_rule_engine.erl
Expand Up @@ -164,15 +164,15 @@ prepare_action({Name, Args}) ->
NewArgs = with_resource_config(Args),
#{name => Name, args => Args, apply => M:F(NewArgs)};
not_found ->
throw(action_not_found)
throw({action_not_found, Name})
end.

with_resource_config(Args = #{'$resource' := ResId}) ->
with_resource_config(Args = #{<<"$resource">> := ResId}) ->
case emqx_rule_registry:find_resource(ResId) of
{ok, #resource{config = Config}} ->
maps:merge(Args, Config);
not_found ->
throw(resource_not_found)
throw({resource_not_found, ResId})
end;

with_resource_config(Args) -> Args.
Expand All @@ -193,6 +193,6 @@ create_resource(#{name := Name,
ok = emqx_rule_registry:add_resource(Resource),
{ok, Resource};
not_found ->
{error, resource_type_not_found}
{error, {resource_type_not_found, Name}}
end.

94 changes: 83 additions & 11 deletions src/emqx_rule_engine_api.erl
Expand Up @@ -34,14 +34,14 @@

-rest_api(#{name => show_rule,
method => 'GET',
path => "/rules/:id",
path => "/rules/:bin:id",
func => show_rule,
descr => "Show a rule"
}).

-rest_api(#{name => delete_rule,
method => 'DELETE',
path => "/rules/:id",
path => "/rules/:bin:id",
func => delete_rule,
descr => "Delete a rule"
}).
Expand All @@ -67,13 +67,27 @@
descr => "A list of all resources"
}).

-rest_api(#{name => create_resource,
method => 'POST',
path => "/resources/",
func => create_resource,
descr => "Create a resource"
}).

-rest_api(#{name => show_resource,
method => 'GET',
path => "/resources/:id",
path => "/resources/:bin:id",
func => show_resource,
descr => "Show a resource"
}).

-rest_api(#{name => delete_resource,
method => 'DELETE',
path => "/resources/:bin:id",
func => delete_resource,
descr => "Delete a resource"
}).

-rest_api(#{name => list_resource_types,
method => 'GET',
path => "/resource_types/",
Expand Down Expand Up @@ -108,16 +122,26 @@
, show_resource_type/2
]).

-define(ERR_NO_ACTION(NAME), list_to_binary(io_lib:format("Action ~s Not Found", [(NAME)]))).
-define(ERR_NO_RESOURCE(RESID), list_to_binary(io_lib:format("Resource ~s Not Found", [(RESID)]))).
-define(ERR_NO_RESOURCE_TYPE(TYPE), list_to_binary(io_lib:format("Resource Type ~s Not Found", [(TYPE)]))).
-define(ERR_BADARGS, <<"Bad Arguments">>).

%%------------------------------------------------------------------------------
%% Rules API
%%------------------------------------------------------------------------------

create_rule(_Bindings, Params) ->
case emqx_rule_engine:create_rule(Params) of
try emqx_rule_engine:create_rule(parse_rule_params(Params)) of
{ok, Rule} ->
return({ok, record_to_map(Rule)});
{error, action_not_found} ->
return({error, 500, "Action Not Found"})
{error, {action_not_found, ActionName}} ->
return({error, 400, ?ERR_NO_ACTION(ActionName)})
catch
throw:{resource_not_found, ResId} ->
return({error, 400, ?ERR_NO_RESOURCE(ResId)});
_Error:_Reason ->
return({error, 400, ?ERR_BADARGS})
end.

list_rules(_Bindings, _Params) ->
Expand Down Expand Up @@ -145,11 +169,16 @@ show_action(#{name := Name}, _Params) ->
%%------------------------------------------------------------------------------

create_resource(#{}, Params) ->
case emqx_rule_engine:create_resource(Params) of
try emqx_rule_engine:create_resource(parse_resource_params(Params)) of
{ok, Resource} ->
return({ok, record_to_map(Resource)});
{error, resource_type_not_found} ->
return({error, 500, "Resource Type Not Found"})
{error, {resource_type_not_found, Type}} ->
return({error, 400, ?ERR_NO_RESOURCE_TYPE(Type)})
catch
throw:{resource_type_not_found, Type} ->
return({error, 400, ?ERR_NO_RESOURCE_TYPE(Type)});
_Error:_Reason ->
return({error, 400, ?ERR_BADARGS})
end.

list_resources(#{}, _Params) ->
Expand Down Expand Up @@ -185,7 +214,7 @@ reply_with(Find, Key) ->
{ok, R} ->
return({ok, record_to_map(R)});
not_found ->
return({error, 404, "Not Found"})
return({error, 404, <<"Not Found">>})
end.

record_to_map(#rule{id = Id,
Expand All @@ -197,7 +226,7 @@ record_to_map(#rule{id = Id,
#{id => Id,
name => Name,
rawsql => RawSQL,
actions => Actions,
actions => [N || #{name := N} <- Actions],
enabled => Enabled,
description => Descr
};
Expand Down Expand Up @@ -232,3 +261,46 @@ record_to_map(#resource_type{name = Name,
description => Descr
}.

parse_rule_params(Params) ->
parse_rule_params(Params, #{}).
parse_rule_params([], Rule) ->
Rule;
parse_rule_params([{<<"name">>, Name} | Params], Rule) ->
parse_rule_params(Params, Rule#{name => Name});
parse_rule_params([{<<"for">>, Hook} | Params], Rule) ->
parse_rule_params(Params, Rule#{for => Hook});
parse_rule_params([{<<"rawsql">>, RawSQL} | Params], Rule) ->
parse_rule_params(Params, Rule#{rawsql => RawSQL});
parse_rule_params([{<<"actions">>, Actions} | Params], Rule) ->
parse_rule_params(Params, Rule#{actions => [parse_action(A) || A <- Actions]});
parse_rule_params([{<<"description">>, Descr} | Params], Rule) ->
parse_rule_params(Params, Rule#{description => Descr});
parse_rule_params([_ | Params], Res) ->
parse_rule_params(Params, Res).

parse_action(Actions) ->
case proplists:get_value(<<"params">>, Actions) of
undefined ->
binary_to_existing_atom(proplists:get_value(<<"name">>, Actions), utf8);
Params ->
{binary_to_existing_atom(proplists:get_value(<<"name">>, Actions), utf8),
maps:from_list(Params)}
end.

parse_resource_params(Params) ->
parse_resource_params(Params, #{}).
parse_resource_params([], Res) ->
Res;
parse_resource_params([{<<"name">>, Name} | Params], Res) ->
parse_resource_params(Params, Res#{name => Name});
parse_resource_params([{<<"type">>, Type} | Params], Res) ->
try parse_resource_params(Params, Res#{type => binary_to_existing_atom(Type, utf8)})
catch error:badarg ->
throw({resource_type_not_found, Type})
end;
parse_resource_params([{<<"config">>, Config} | Params], Res) ->
parse_resource_params(Params, Res#{config => maps:from_list(Config)});
parse_resource_params([{<<"description">>, Descr} | Params], Res) ->
parse_resource_params(Params, Res#{description => Descr});
parse_resource_params([_ | Params], Res) ->
parse_resource_params(Params, Res).

0 comments on commit ed16002

Please sign in to comment.