{"error":"bad_request","reason":"attachments not supported in Couchbase"}

hi,
i try to use lcb_make_http_request to get data from view, it return LCB_SUCCESS but the response is :
{"error":"bad_request","reason":"attachments not supported in Couchbase"}
what this mean?
I run the uri in web browser, i can get result
host:8092/bucketname/_design/dev_prod/_view/view_name?startkey="123456789"&limit=10

similar question has been asked, but no answer yet:
http://www.couchbase.com/forums/thread/python-client-delete-design-doc

thanks!

Could you post a snippet of code you are using to make a query?

2 Answers

« Back to question.

hi, avsej:
couple questions regarding the c code:
1. i use data_callback instead of complete_callback

2. i use LCB_HTTP_METHOD_GET not POST or PUT, because i intend to get something from view
so cmd.v.v0.body is empty, cmd.v.v0.nbody == 0,

3. should we assign full path to cmd.v.v0.path ? like:
string uri = host + ":" + VIEW_PORT + "/" + _bucketname + "/_design/"+_designdocname + "/_view/" + _viewname +"?key="+ "\"" + _key +"\"";

my code:

lcb_error_t err;
lcb_http_cmd_t cmd;
string uri;
uri	= host + ":" + VIEW_PORT + "/" + _bucketname + "/_design/"+_designdocname + "/_view/" + _viewname +"?startkey="+ "\"" + _key +"\"";
 
if(_pageId > 1)
{
		uri	+= "&startkey_docid=" + _lastDocID;
		uri += "&skip=1";
}
	if(_limit > 0)
	{
		stringstream ss;
		ss << _limit;
		uri += "&limit=" + ss.str();
	}
	std::cout<<"uri:"<<uri<<std::endl;
	size_t nbytes = 0;
	const char * bytes = _postData.c_str();
    if (bytes) {
        nbytes = strlen(bytes);
    }
	cmd.version = 0;
    cmd.v.v0.path = uri.c_str();
    cmd.v.v0.npath = strlen(uri.c_str());
    cmd.v.v0.body = bytes;
    cmd.v.v0.nbody = nbytes;
    cmd.v.v0.method = bytes ? LCB_HTTP_METHOD_POST : LCB_HTTP_METHOD_GET;
    cmd.v.v0.chunked = true;
    cmd.v.v0.content_type = "application/json";
	err = lcb_make_http_request(instance, (void *)this, LCB_HTTP_TYPE_VIEW, &cmd, NULL);
	if (err != LCB_SUCCESS) {
        fprintf(stderr, "Failed to get view by key: %s\n",
                lcb_strerror(NULL, err));
        return false;
    }
	lcb_wait(instance);
	_response = outResponse;
	return true;	
static void data_callback(lcb_http_request_t request,
                          lcb_t instance,
                          const void *cookie,
                          lcb_error_t error,
                          const lcb_http_resp_t *resp)
{
    if (error != LCB_SUCCESS) {
        return;
    }
    CouchbaseHandler *couchbaseHandler;
    couchbaseHandler 
	= const_cast<CouchbaseHandler *>(reinterpret_cast<const CouchbaseHandler *>(cookie));
 
    string response;
	if(resp->v.v0.bytes)
	{
		response.assign((const char*)resp->v.v0.bytes,resp->v.v0.nbytes);
		couchbaseHandler->setOutResponse(response);
	}
 
}

note that i assigned outResponse with response from view in data_callback.

thanks!

It should be

"/_design/"+_designdocname + "/_view/" + _viewname +"?startkey="+ "\"" + _key +"\""
« Back to question.

I get the same thing following the REST API to a T to create a new view. Even though the documentation says to use an attachment. My guess is the documentation is wrong.

Here is an example of my restful call that fails

curl -X PUT -H 'Content-Type: application/json' http://user:password@localhost:8092/bucket/_design/name/newView -d @newView.ddoc

And the response:
{"error":"bad_request","reason":"attachments not supported in Couchbase"}

I've found a lot of the REST API documentation to be completely inaccurate or just doesn't work, which makes it rather difficult to extend and incorporate couchbase into any environment.

looks like I'm not the only one get this error. is it a bug?

You are doing something wrong. I've just checked and it works:

$ curl -v -X PUT -H 'Content-Type: application/json' http://node.avsej.net:8092/default/_design/blog -d'{"_id":"_design/blog","language":"javascript","views":{"recent_posts":{"map":"function(doc){if(doc.date&&doc.title){emit(doc.date,doc.title);}}"}}}'
* About to connect() to node.avsej.net port 8092 (#0)
*   Trying 50.116.6.84...
* Adding handle: conn: 0xa51e10
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0xa51e10) send_pipe: 1, recv_pipe: 0
* Connected to node.avsej.net (50.116.6.84) port 8092 (#0)
> PUT /default/_design/blog HTTP/1.1
> User-Agent: curl/7.31.0
> Host: node.avsej.net:8092
> Accept: */*
> Content-Type: application/json
> Content-Length: 147
> 
* upload completely sent off: 147 out of 147 bytes
< HTTP/1.1 201 Created
* Server MochiWeb/1.0 (Any of you quaids got a smint?) is not blacklisted
< Server: MochiWeb/1.0 (Any of you quaids got a smint?)
< Location: http://node.avsej.net:8092/default/_design/blog
< Date: Thu, 25 Jul 2013 05:40:42 GMT
< Content-Type: text/plain;charset=utf-8
< Content-Length: 32
< Cache-Control: must-revalidate
< 
{"ok":true,"id":"_design/blog"}
* Connection #0 to host node.avsej.net left intact

Also example, based on lcb_make_http_request manpage works well too:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libcouchbase/couchbase.h>
 
static void error_callback(lcb_t instance, lcb_error_t error, const char *errinfo)
{
    fprintf(stderr, "ERROR: %s (0x%x), %s\n", lcb_strerror(instance, error), error, errinfo);
    exit(EXIT_FAILURE);
}
 
static void complete_callback(lcb_http_request_t req, lcb_t instance,
                              const void *cookie, lcb_error_t error,
                              const lcb_http_resp_t *resp)
{
    size_t ii;
 
    if (resp->v.v0.headers) {
        const char *const *headers = resp->v.v0.headers;
        for (ii = 1; *headers != NULL; ++ii, ++headers) {
            fprintf(stderr, "%s%s", *headers, (ii % 2 == 0) ? "\n" : ": ");
        }
    }
    fprintf(stderr, "\"");
    fwrite(resp->v.v0.path, sizeof(char), resp->v.v0.npath, stderr);
    fprintf(stderr, "\": ");
    if (error == LCB_SUCCESS) {
        fprintf(stderr, "OK Size: %d", (int)resp->v.v0.nbytes);
        fwrite(resp->v.v0.bytes, sizeof(char), resp->v.v0.nbytes, stdout);
    } else {
        fprintf(stderr, "FAIL(%d) %s Status:%d Size:%d\n",
                error, lcb_strerror(instance, error),
                resp->v.v0.status, (int)resp->v.v0.nbytes);
    }
    fwrite(resp->v.v0.bytes, sizeof(char), resp->v.v0.nbytes, stdout);
    fprintf(stderr, "\n");
    (void)req;
    (void)cookie;
}
 
int main(int argc, char *argv[])
{
    lcb_error_t err;
    lcb_t instance;
    struct lcb_create_st create_options;
 
    memset(&create_options, 0, sizeof(create_options));
 
    create_options.v.v0.host = "node.avsej.net:8091";
    create_options.v.v0.bucket = "default";
    create_options.v.v0.user = NULL;
    create_options.v.v0.passwd = NULL;
    err = lcb_create(&instance, &create_options);
    if (err != LCB_SUCCESS) {
        fprintf(stderr, "Failed to create libcouchbase instance: %s\n", lcb_strerror(NULL, err));
        return 1;
    }
    (void)lcb_set_error_callback(instance, error_callback);
    /* Initiate the connect sequence in libcouchbase */
    if ((err = lcb_connect(instance)) != LCB_SUCCESS) {
        fprintf(stderr, "Failed to initiate connect: %s\n", lcb_strerror(NULL, err));
        lcb_destroy(instance);
        return 1;
    }
    (void)lcb_set_http_complete_callback(instance, complete_callback);
    /* Run the event loop and wait until we've connected */
    lcb_wait(instance);
 
    {
        const char docid[] = "_design/test2";
        const char doc[] = "{\"views\":{\"all\":{\"map\":\"function (doc, meta) { emit(meta.id, null); }\"}}}";
        lcb_http_cmd_t cmd;
        lcb_http_request_t req;
	lcb_error_t err;
 
        cmd.version = 0;
        cmd.v.v0.path = docid;
        cmd.v.v0.npath = strlen(docid);
        cmd.v.v0.body = doc;
        cmd.v.v0.nbody = strlen(doc);
        cmd.v.v0.method = LCB_HTTP_METHOD_PUT;
        cmd.v.v0.content_type = "application/json";
        err = lcb_make_http_request(instance, NULL, LCB_HTTP_TYPE_VIEW, &cmd, &req);
        if (err != LCB_SUCCESS) {
            fprintf(stderr, "Failed to schedule HTTP request: %s\n", lcb_strerror(instance, err));
            lcb_destroy(instance);
            return 1;
        }
        lcb_wait(instance);
    }
    lcb_destroy(instance);
 
    return 0;
}

Thanks for the detailed comment. I was definitely doing it wrong, and missing the appropriate views, and map definition in my json. Not to mention having unescaped carriage returns (which produces a different , but accurate error).