JSON ошибка форматирования при попытке POST или PUT с использованием express4-tedious - PullRequest
0 голосов
/ 22 марта 2020

Приложение sql -server-samples 'Todo', которое я пытаюсь получить, находится здесь . Он должен превратить серверную базу данных SQL в API REST с очень небольшим количеством строк кода.

Я не могу выполнить POST или PUT. Выдает ошибку

message: "JSON text is not properly formatted. Unexpected character 'o' is found at position 1.",
code: 'EREQUEST',
number: 13609,
state: 4,
class: 16,
serverName: 'SERVER',
procName: 'createTodo',
lineNumber: 4

Нет проблем с GET, GET по id или DELETE. GET и DELETE отлично работают с SQL Server 2017 Developer, Express и Azure SQL База данных.

Нет ошибок при запуске самих хранимых процедур из SQL Server или Azure. Только при попытке выполнить POST или PUT из командной строки я получаю сообщение об ошибке:

curl -X "POST" "http://localhost:3000/todo"
-i
-H 'Content-Type: application/json'
-d '{"title": "test_title", "description": "test_description", "completed": false, "dueDate": "2014-12-14T00:00:00.000Z"}'

Не вижу ничего плохого в самом тексте JSON. Не вижу никакого символа 'o' в позиции 1. Я попробовал почти все варианты, которые есть с nvarchar, varchar, используя N 'против' в начале строки JSON, изменил описание, чтобы описать, думая, что это может быть зарезервированное слово в SQL Server 2017, похоже, ничего не работает.

Сообщение об ошибке при использовании Azure SQL База данных немного отличается:

JSON text is not properly formatted. Unexpected character \'o\' is found at position 1.

app. js

var express = require('express');
var config = require('config');
var bodyParser = require('body-parser');
var tediousExpress = require('express4-tedious');

var app = express();
app.use(function (req, res, next) {
    req.sql = tediousExpress(config.get('connection'));
    next();
});

app.use(bodyParser.text()); 
app.use('/todo', require('./routes/todo'));

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found: '+ req.method + ":" + req.originalUrl);
    err.status = 404;
    next(err);
});
app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
    console.log('Express server listening on port ' + server.address().port);
});

module.exports = app;

todo. js

var router = require('express').Router();
var TYPES = require('tedious').TYPES;

/* GET task listing. */
router.get('/', function (req, res) {

    req.sql("select * from todo for json path")
        .into(res, '[]');

});

/* GET single task. */
router.get('/:id', function (req, res) {

    req.sql("select * from todo where id = @id for json path, without_array_wrapper")
        .param('id', req.params.id, TYPES.Int)
        .into(res, '{}');

});

/* POST create task. */
router.post('/', function (req, res) {

    req.sql("exec createTodo @todo")
        .param('todo', req.body, TYPES.NVarChar)
        .exec(res);

});

/* PUT update task. */
router.put('/:id', function (req, res) {

    req.sql("exec updateTodo @id, @todo")
        .param('id', req.params.id, TYPES.Int)
        .param('todo', req.body, TYPES.NVarChar)
        .exec(res);

});

/* DELETE single task. */
router.delete('/:id', function (req, res) {

    req.sql("delete from todo where id = @id")
        .param('id', req.params.id, TYPES.Int)
        .exec(res);

});

module.exports = router;

default. json

{
    "connection":{
        "server"  : "<name>.database.windows.net",
        "userName": "username",
        "password": "password",
        "options": { "encrypt": "true", "database": "<azure-database-name>" }
    }
}

setup. sql - образец таблицы Todo и хранимые процедуры для POST и PUT

/*
CREATE DATABASE TodoDb;
USE TodoDb;
*/
DROP TABLE IF EXISTS Todo
DROP PROCEDURE IF EXISTS createTodo
DROP PROCEDURE IF EXISTS updateTodo
GO

CREATE TABLE Todo (
    id int IDENTITY PRIMARY KEY,
    title nvarchar(30) NOT NULL,
    description nvarchar(4000),
    completed bit,
    dueDate datetime2 default (dateadd(day, 3, getdate()))
)
GO

INSERT INTO Todo (title, description, completed, dueDate)
VALUES
('Install SQL Server 2016','Install RTM version of SQL Server 2016', 0, '2017-03-08'),
('Get new samples','Go to github and download new samples', 0, '2016-03-09'),
('Try new samples','Install new Management Studio to try samples', 0, '2016-03-12')

GO

create procedure dbo.createTodo(@todo nvarchar(max))
as begin
    insert into Todo
    select *
    from OPENJSON(@todo) 
            WITH (  title nvarchar(30), description nvarchar(4000),
                    completed bit, dueDate datetime2)
end
GO

create procedure updateTodo(@id int, @todo nvarchar(max))
as begin
    update Todo
    set title = json.title, description = json.description,
        completed = json.completed, dueDate = json.dueDate
    from OPENJSON( @todo )
            WITH(   title nvarchar(30), description nvarchar(4000),
                    completed bit, dueDate datetime2) AS json
    where id = @id
end
go

select * from todo for json path

1 Ответ

1 голос
/ 22 марта 2020

Я думаю, что есть небольшая ошибка. Вы используете body-parser.text(), но отправляете данные как JSON. Измените запрос скручивания, как показано ниже:

 curl -X "POST" "http://localhost:3000/todo" -i -H 'Content-Type: text/plain' -d '{"title": "test_title", "description": "test_description", "completed": false, "dueDate": "2014-12-14T00:00:00.000Z"}'

Кроме того, вы можете использовать Postman для тестирования API, что более удобно
enter image description here

Убедитесь, что строка JSON, переданная процедуре, должна быть точной. Вы можете проверить ввод в процедуру, запустив следующий скрипт:

DECLARE @json NVARCHAR(MAX)

SET @json='{"name":"John","surname":"Doe","age":45,"skills":["SQL","C#","MVC"]}';

SELECT *
FROM OPENJSON(@json);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...