Trouble saving attachment via CBL Listener (REST API)


#1

Hello,

I am trying to save an attachment through the CBL REST API, but get an “Invalid attachment” response with a 400 http status. Saving/Updating/Querying/Deleting documents work fine.

Here is the output when I enable logging with the CBLListenerVerbose tag: https://gist.github.com/VonD/58a33a14ff53378afd37

Here is my code in javascript (it is a ReactNative app):

fetch(couchbaseURL + documentID + "?rev=" + documentRevision, {
    method: "PUT",
    body: "This is my text",
    headers: { "Content-Type": "text/plain" }
}).then(function(response){ ... });

Do I do something wrong ? How can I get more information about why the attachment is invalid ?

Many thanks for your help,

Paul


#2

It looks like you’re saving a document, not an attachment, except you’re sending the body as plain text instead of JSON. If you want to create an attachment through a REST call, the easiest way is to do a PUT to the URL of the attachment. That means you need to add the attachment name as a component of the URL. In your example, change the first line to

fetch(couchbaseURL + documentID + "/" + attachmentName + "?rev=" + documentRevision, {

#3

Many thanks for the quick reply. This is a typo on my part : the actual URL i use includes the attachment name as you wrote it:

fetch(couchbaseURL + documentID + "/note.txt" + "?rev=" + documentRevision, {

#4

It looks correct as far as I can tell, but I don’t know the JavaScript API. Is there a way you can find out exactly what headers and body are being sent? (Whatever you did to turn on CBLListenerVerbose logging didn’t work, or it would have logged that.)


#5

Also: Are you certain the document already exists? (If it doesn’t exist, you have to leave off the ?rev= query.)


#6

OK, I’ll try to figure out what headers and body are being sent, thanks.

I enabled logging with

[CBLManager enableLogging: @"CBLListenerVerbose"];

in application didFinishLaunchingWithOptions in the AppDelegate file.

I think the document exists, as wrapping the above code in a GET call to retrieve the document with the given id and revision returns the document and yields the same result.


#7

Ah, there’s an annoying bug that prevents listener logging options from being set by CBLManager. If you have access to the command-line flags (i.e. if you’re running the app from an Xcode project) you can add -Log YES -Log CBLListenerVerbose as flags.


#8

Sorry to ask you this - but the output of logging is to be found in the Xcode console right ?

I added the two flags and the only new output I can find is

Logging CBLListener, CBLListenerVerbose to TTY

thanks again for your help


#9

In case it can help, here is the logs output after enabling CBL_Router

10:31:30.414‖ CBL_Router: PUT http://lite.couchbase./planity/416410a3-8cd7-4e78-9684-e86346f49a74/attachment.txt?rev=1-191cf9b2c01471114a2bbef24f77aab8 + body stream
Content-Type: text/plain
Content-Length: 15

10:31:30.415‖ CBL_BlobStore /Users/paul/Library/Developer/CoreSimulator/Devices/20578BD8-AE31-44B4-BB28-1593199B61C0/data/Containers/Data/Application/86111FD6-DE95-4AE4-B469-6DAAA9D28336/Library/Application Support/CouchbaseLite/planity attachments created tempDir /Users/paul/Library/Developer/CoreSimulator/Devices/20578BD8-AE31-44B4-BB28-1593199B61C0/data/Containers/Data/Application/86111FD6-DE95-4AE4-B469-6DAAA9D28336/Library/Application Support/CouchbaseLite/(A Document Being Saved By PlanityIOSApp 24)

10:31:30.416‖ CBL_Router: Response – status=400, body=43 bytes
Server: CouchbaseLite 1.0 (unofficial)
Content-Type: application/json

thanks


#10

I tried this from the Chrome console and the attachment is saved correctly in CBLite (v1.0.4).
Is the request working in the Chrome console for you?

var url = 'http://localhost:64943/db';
// add attachment to existing doc
fetch(url + '/doc-1234/notes.txt?rev=2-99de4882df335ecae91a75a9b2bb930c',
 {method: 'PUT', body: 'some text', headers: { 'Content-Type': 'text/plain' }})
.then(function(res) {
  return res.json();
})
.then(function(jsonRes) {
  console.log(jsonRes)
});

// console.log output
Object {id: "doc-1234", rev: "3-76d42a0a45568bdbad4fc698fa04b1bb", ok: true}

#11

Hi, same result for me from the Chrome console:

fetch('http://lite.couchbase./planity/416410a3-8cd7-4e78-9684-e86346f49a74/attachment.txt?rev=1-191cf9b2c01471114a2bbef24f77aab8',{method: 'PUT', body: 'some text', headers: { 'Content-Type': 'text/plain' }})
.then(function(res) {
  return res.json();
})
.then(function(jsonRes) {
  console.log(jsonRes)
});

// console.log output
Object {status: 400, error: "Invalid attachment"}

I am also using CBLite 1.4.0


#12

We didn’t have a unit test covering this exact situation (PUT to an attachment URL for a doc that already exists), but I just wrote one and it runs successfully.

Hi, same result for me from the Chrome console:

I don’t see how the code you show can work in the Chrome console, because “lite.couchbase.” isn’t a valid hostname except inside an app using Couchbase Lite. Please show the exact text you ran in Chrome.


#13

This is the exact code. The Chrome console thing is a feature of ReactNative : it lets you execute some js in the context of the app.

I tried a PUT request to an attachment URL for a doc not yet existing - with the same result.


#14

Ah, got it. Sorry for misunderstanding.

I don’t know why it’s not working for you. But in any case, this is not the best way to create an attachment, it’s just a convenience. The best way is to PUT the document with an _attachment property containing the metadata and data of the attachment(s). I don’t know if our own REST docs cover this in enough detail, but it’s identical to CouchDB and there’s plenty of documentation of that.


#15

@jamiltz I would be curious to know your setup : what version of RN are you using ? Is it an app created with the react-native init command or did you add it to an existing app ? What edition of CB lite are you using? Thanks a lot.


#16

@jens ok, thanks for the info.

Putting with the _attachments property seems to work ok, but when I update the document without including again the attachments, they seem to be deleted : is this the intended behavior ?

Also, can I use this documentation of CouchDB in general for CBL Listener ? Thanks.


#17

Sorry I tried the fetch api available in the latest version of Chrome. I will try in a React Native app and let you know the result.

James


#18

The _attachments property is part of the document. Any time you save a new revision of the document, it has to include all the properties you want to be in the document; it’s not incremental. In other words, you have to preserve the _attachments property (unless you want to remove some or all of the attachments, of course.)

In general, you update documents incrementally by first doing a GET, modifying the properties you want to change, then PUTting those.


#19

@jens OK, very clear. Thanks a lot for all your help.

@jamiltz that would be very kind of you. I’m still intrigued why the first method didn’t work for me. Many thanks.


#20

Does any one know how to PUT an image attachment via the REST API? How should the body be encoded?