confluentinc / ksql

The database purpose-built for stream processing applications.
https://ksqldb.io
Other
127 stars 1.04k forks source link

ksqlDB REST API problem #7610

Closed achakhalyan closed 3 years ago

achakhalyan commented 3 years ago

Describe the bug I am using node.js to run push and pull queries in your rest API. I have to get following error {"@type":"generic_error","error_code":40000,"message":"Invalid JSON in request: No content to map due to end-of-input\n at [Source: (byte[])\"\"; line: 1, column: 0]"}

I am using this part of code const http2 = require('http2'); const http2PostRequest = (url, path, body) => new Promise((resolve) => { const buffer = new Buffer.from(JSON.stringify(body)); console.log(' http2.constants.HTTP2_METHOD_POST => ', http2.constants.HTTP2_METHOD_POST) console.log(' http2.constants.HTTP2_METHOD_POST => ',${path}`); const req = client.request({

    [http2.constants.HTTP2_HEADER_METHOD]: http2.constants.HTTP2_METHOD_POST,
    [http2.constants.HTTP2_HEADER_PATH]: `${path}`,
    "Content-Type": "application/vnd.ksqlapi.delimited.v1",
    "Accept": "application/vnd.ksqlapi.delimited.v1",
    "Content-Length": buffer.length,
    "body": body (also used buffer)
});

req.setEncoding('utf8');

let data = [];
req.on('data', (chunk) => {
    console.log('chunk => ', chunk);
    data.push(chunk);
});
req.end();
req.on('end', () => {
    resolve({data: data.join()});
});

});

const body = { "sql": "SELECT * FROM USERPROFILE EMIT CHANGES;", "properties": {"ksql.streams.auto.offset.reset": "earliest"} }; http2PostRequest( "http://g6-dev2:8088", "/query-stream", JSON.stringify(body) ).then((res) => { console.log('res => ', res); })`

To Reproduce Steps to reproduce the behavior, include:

  1. The version of KSQL - CLI v6.1.1, Server v6.1.1 located at http://localhost:8088.
  2. Sample source data - no.
  3. Any SQL statements you ran - yes

Expected behavior I want to get a response of push request

Actual behaviour A clear and concise description of what actually happens, including:

  1. CLI output - ok
  2. Error messages - no
  3. KSQL logs

Additional context Add any other context about the problem here.

OneCricketeer commented 3 years ago

The error is saying that you have an escaped quote, which is probably because you used JSON.stringify() when you didn't need to. Specifically, buffer is JSONified twice

Also note, http2 module is deprecated; https://www.npmjs.com/package/http2

Are you able to reproduce the problem using cURL?

achakhalyan commented 3 years ago

Yes, I have to get a successful response when using cURL. Inksql documentation says that endpoint will use http/2 request.

I have got the same problem when using without JSON.stringify() what module do You offer when I am using node.js?

OneCricketeer commented 3 years ago

what module do You offer

Sorry, wasn't clear if you're using external dependency or the built in one.

Can you share the working curl request for comparison? Are you sure that you translated into JS correctly?

achakhalyan commented 3 years ago

curl --http2 "POST" "http://localhost:8088/query-stream" -d $'{"sql": "SELECT * FROMUSERPROFILEEMIT CHANGES;", "properties": {"ksql.streams.auto.offset.reset": "earliest" } }' - I am using that http/2 request working well, get successful response also listen any stream. In Node.js I faceup a big problem. node.js code is following

const http2 = require('http2');
const http2PostRequest = (url, path, body) => new Promise((resolve) => {
    console.log('url => ', url);
    console.log('path => ', path);
    console.log('body => ', body);
    const client = http2.connect(url);
    console.log(' http2.constants.HTTP2_METHOD_POST => ',  http2.constants.HTTP2_METHOD_POST)
    console.log(' http2.constants.HTTP2_METHOD_POST => ',  `${path}`);
    const req = client.request({
        [http2.constants.HTTP2_HEADER_SCHEME]: "https",
        ":method": "POST",
        ":path": path,
        // "Content-Type": "application/vnd.ksqlapi.delimited.v1",
        // "Accept": "application/vnd.ksqlapi.delimited.v1",
        "Content-type": "application/json",
        "body": body
    });

    req.setEncoding('utf8');

    req.on('response', (headers, flags) => {
        console.log('headers => ', headers);
    });

    let data = [];
    req.on('data', (chunk) => {
        console.log('chunk => ', chunk);
        data.push(chunk);
    });

    req.end();
    req.on('end', () => {
        resolve({data: data.join()});
    });
});

const body = {
    "sql": "SELECT * FROM `USERPROFILE` EMIT CHANGES;",
    "properties": {"ksql.streams.auto.offset.reset": "earliest"}
};
http2PostRequest(
    "http://localhost:8088",
    "/query-stream",
    JSON.stringify(body)
).then((res) => {
    console.log('res => ', res);
})

Error is this {"@type":"generic_error","error_code":40000,"message":"Invalid JSON in request: No content to map due to end-of-input\n at [Source: (byte[])\"\"; line: 1, column: 0]"}

achakhalyan commented 3 years ago

I have solved the problem. If anyone needs a cane to use the following code

const http2 = require('http2');
const http2PostRequest = (url, path, data) => new Promise((resolve, reject) => {
    console.log('url => ', url);
    console.log('data => ', data);

    const client = http2.connect(url);
    console.log(' http2.constants.HTTP2_METHOD_POST => ', http2.constants.HTTP2_METHOD_POST)
    console.log(' http2.constants.HTTP2_PATH => ', `${path}`);

    const req = client.request({
        [http2.constants.HTTP2_HEADER_SCHEME]: "https",
        'Content-Type': 'application/json',
        'Content-Length': data.length,
        ":method": "POST",
        ":path": path
    });
    req.setEncoding('utf8');
    req.on('response', (headers, flags) => {
        console.log('headers => ', headers);
        console.log('flags => ', flags);

        req.on('data', d => {
            console.log('data => ', JSON.parse(d));
        })

        req.on('close', () => {
            try {
                resolve(data);
            } catch (e) {
                resolve(e);
            }
        })
        req.on('error', error => {
            reject(error);
        })
    });
    req.write(data);
    req.end();
});

const data = {
    "sql": "SELECT * FROM `FOO_02` EMIT CHANGES;",
    "properties": {"ksql.streams.auto.offset.reset": "earliest"}
};
http2PostRequest(
    "http://localhost:8088",
    "/query-stream",
    JSON.stringify(data)
).then((res) => {
    console.log('res => ', res);
})
OneCricketeer commented 3 years ago

Seems to me like you never use const data anywhere except to return the req.write

You also shouldn't nest different req.on events