basho-labs / riak_explorer

Riak dev-mode and admin GUI
Apache License 2.0
60 stars 15 forks source link

Enable users to create+activate bucket types via Explorer API #97

Open dmitrizagidulin opened 8 years ago

dmitrizagidulin commented 8 years ago

The ability to create new Bucket Types via HTTP API is one of the most often-asked-for features, by users.

Implement the following API call (this example creates a new bucket type named my-new-type):

curl -XPUT /explore/clusters/$cluster/bucket_types/my-new-type -d '{"props":{ ... }}' -H 'Content-Type: application/json'

Note that this is different from issue #96 (Edit bucket type properties), since the edit properties call is to .../$type/props, and the create new call is to .../$type

drewkerrigan commented 8 years ago

@dmitrizagidulin This already exists I believe: https://github.com/basho-labs/riak_explorer/blob/master/src/re_wm_bucket_type.erl#L133-L139

Please test and let me know if it works for you. Caveat: You'll need to do the PUT twice in order to activate it (first one creates, second one activates).

dmitrizagidulin commented 8 years ago

Tested, ran into some issues:

  1. A plain PUT with no Content-Type header and no payload (curl -XPUT localhost:9000/explore/clusters/localdev/bucket_types/new-type) results in a 415 Unsupported Media Type. This is sort of fine, but would be better to have it work without a header and payload (basically, a plain PUT would be the equivalent of doing riak-admin bucket-type create new-type on the cli, with no props json).
  2. Adding an Accept: application/json header (but no payload) (curl -XPUT localhost:9000/explore/clusters/localdev/bucket_types/new-type -v -H 'Content-Type: application/json') resulted in a 204 No Content, which is great, except that it resulted in no bucket type being created (I verified this via riak-admin bucket-type list).

    Incidentally -- and I didn't know this before starting to wrangle AJAX in Ember, but apparently it's against the JSON spec to have a Content-Type: application/json header but with an empty body/contents. Like, a browser's AJAX straight up raises a parsing exception. I'm not saying we should worry about that part excessively here, but figured you'd be amused to know.

  3. Adding an Accept header with an empty props json (curl -XPUT localhost:9000/explore/clusters/localdev/bucket_types/new-type -v -H 'Content-Type: application/json' -d '{"props":{}}') does create the bucket type, but also results in a 500 Server Error:

    {error,
    {throw,
       {unknown_capability,{riak_core,bucket_types}},
       [{riak_core_capability,get,1,
            [{file,"src/riak_core_capability.erl"},{line,140}]},
        {riak_core_bucket_type,activate,1,
            [{file,"src/riak_core_bucket_type.erl"},{line,170}]},
        {re_riak,create_bucket_type,3,[{file,"src/re_riak.erl"},{line,825}]},
        {re_wm_bucket_type,accept_content,2,
            [{file,"src/re_wm_bucket_type.erl"},{line,123}]},
        {webmachine_resource,resource_call,3,
            [{file,"src/webmachine_resource.erl"},{line,186}]},
        {webmachine_resource,do,3,
            [{file,"src/webmachine_resource.erl"},{line,142}]},
        {webmachine_decision_core,resource_call,1,
            [{file,"src/webmachine_decision_core.erl"},{line,48}]},
        {webmachine_decision_core,accept_helper,1,
            [{file,"src/webmachine_decision_core.erl"},{line,616}]}]}}
  4. I was not able to activate the newly-created bucket type with a subsequent PUT, however. A plain second PUT (with no header or payload) resulted in the same 415 Unsupported Media Type. A second PUT with a JSON content-type header but no payload resulted in 204 Accepted but no other effect. And a PUT with the header and empty props JSON resulted in the same 500 error as above.

Oh, one other thing. Would it be possible to return different responses based on whether the bucket type was created or activated? Sort of like:

1st PUT:
200 OK
{"message":"Bucket type created."}

2nd PUT:
200 OK
{"message":"Bucket type activated."}

Actually, wait. Can we just make it so that one PUT creates AND activates a bucket type? The whole two-step create+activate thing was only done for the whole downgrade back to 1.4 reasons. We don't really need to worry about it in this project. There's never going to be a situation where a user wants to create a bucket type but not activate it.

So, kicking it back over to ya.

drewkerrigan commented 8 years ago

I've addressed all your comments.

Putting without a content type should give:

{"new-type":{"success":true,"actions":{"create":"Bucket type created.","activate":"Bucket type activated."}},"links":{"self":"/explore/clusters/localdev/bucket_types/new-type6"}}

Putting with content type + valid props should give the same.

Putting with invalid props should give

{"error":"Cannot create bucket type: no props field found in json."}%

or

{"error":"Cannot create bucket type: invalid json."}%

Putting against the same bucket type with new props (update) should give:

{"new-type5":{"success":true,"actions":{"update":"Bucket type updated."}},"links":{"self":"/explore/clusters/localdev/bucket_types/new-type5"}}
dmitrizagidulin commented 8 years ago

Testing the updates against master, running into error.

The first time I do a PUT, to create & activate a new bucket type, it gives me an error:

curl -XPUT localhost:9000/explore/clusters/localdev/bucket_types/new-type4
< HTTP/1.1 500 Internal Server Error
{
    "error": "Error activating bucket type: not_ready"
}

But doing a second PUT seems to work (though I don't see a create success message like in your sample output -- which is fine, but I thought I'd mention it).

curl -XPUT localhost:9000/explore/clusters/localdev/bucket_types/new-type4
{
    "links": {
        "self": "/explore/clusters/localdev/bucket_types/new-type4"
    },
    "new-type4": {
        "actions": {
            "activate": "Bucket type activated."
        },
        "success": true
    }
}
dmitrizagidulin commented 8 years ago

Submitting an invalid JSON payload does return the correct error:

curl -XPUT localhost:9000/explore/clusters/localdev/bucket_types/new-type6 \
    -d '{"props":{ ... }}' -H 'Content-Type: application/json' -v
< HTTP/1.1 500 Internal Server Error
{"error":"Cannot create bucket type: invalid json."}

Same thing with the {"error":"Cannot create bucket type: no props field found in json."} error.

It should be a 400 Bad Request, though, if at all possible, instead of a 500.