json-server icon indicating copy to clipboard operation
json-server copied to clipboard

File Upload

Open schacki opened this issue 7 years ago • 22 comments

I would really like to use json-server also to upload files. From the documentation and the code, this feature does not seem to be available, correct? Any plans here or ideas, how to implement?

schacki avatar Apr 29 '17 07:04 schacki

Looking to solve the same problem. You can use base64-conversion and store the files as strings, which is probably the easiest.

DanielJackson-Oslo avatar May 13 '17 12:05 DanielJackson-Oslo

also using json-server as a mock server for my frontend SPA. if formData cannot be submitted, i have trouble testing signup requests and any other file uploading requests. this makes the project seem turning into a full-featured server, something like lightweight Mongo + Express but it's still nice to have all the common features modern web utilize. Who knows this will turn into a whole new framework...

fsw0422 avatar May 18 '17 19:05 fsw0422

@fsw0422 : I think form data can be submitted via post or put requests, or am I wrong? my problem are files, which cannot simply be added to the db.json, unless stored as base64 encoded, which I would like to avoid.

schacki avatar May 20 '17 17:05 schacki

I eventually solved it by simply creating a basic file server, uploading the files there, and storing a reference to them here. Took about 10-30 min total.

2017-05-20 19:07 GMT+02:00 schacki [email protected]:

@fsw0422 https://github.com/fsw0422 : I think form data can be submitted via post or put requests, or am I wrong? my problem are files, which cannot simply be added to the db.json, unless stored as base64 encoded, which I would like to avoid.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/typicode/json-server/issues/528#issuecomment-302886046, or mute the thread https://github.com/notifications/unsubscribe-auth/AONvyr0P2CIvsOXL7_IAUDNCjFNbrwRLks5r7x3ugaJpZM4NMLoP .

DanielJackson-Oslo avatar May 26 '17 09:05 DanielJackson-Oslo

so you created a fileserver outside of this project on a separate machine? that was not exactly I was looking for. Or did I misunderstand you?

ghost avatar May 26 '17 11:05 ghost

@DanielJackson-Oslo this is pretty cool, can you share your solution (even if it is super hacky :))

webuniverseio avatar May 31 '17 14:05 webuniverseio

@mswag On the same machine, but yes.

@szarouski Sure! Haven't cleaned the code, and it'll have some project specific stuff in it that you probably don't need, but here it is:

Simple PHP script for handling file uploads (or outputting a form for testing the script):

<?php

if (isset($_FILES["fileToUpload"]["name"])) {

    $target_dir = "/var/www/html/prototype/files/";
    $target_file = $target_dir . basename($_POST["newName"]);
    $uploadOk = 1;
    $imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);

    // Check if file already exists
    if (file_exists($target_file)) {
        echo "Sorry, file already exists.";
        $uploadOk = 0;
    }
    // Check file size
    if ($_FILES["fileToUpload"]["size"] > 100000000) {
        echo "Sorry, your file is too large.";
        $uploadOk = 0;
    }
    // Check if $uploadOk is set to 0 by an error
    if ($uploadOk == 0) {
        echo "Sorry, your file was not uploaded.";
    // if everything is ok, try to upload file
    } else {
        if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
            echo "The file ". basename( $_POST["newName"] ). " has been uploaded.";
        } else {
            echo "Sorry, there was an error uploading your file.";
        }
    }
} else {
?>
<form action="upload_file.php" method="POST" enctype="multipart/form-data">
    <input type="file" name="fileToUpload">
    <input type="text" name="newName" value="test">
    <input type="submit">
</form>
<?php
}
?>

Then just make sure the script has write access to the folder it's supposed to store things in.

On the other end, jQuery to store the file the right place and a reference to the file in json-server:

function uploadReceipt(element) {

    var file = element.files[0];

    var newName = "file-" + Date.now() + "--originally-" + file.name;
    var fileURL = "files/" + newName;

    var form_data = new FormData();
    form_data.append("fileToUpload", file);
    form_data.append("newName", newName);

    $.ajax({
            url: "upload_file.php",
            type: 'POST',
            contentType: false,
            data: form_data,
            cache: false,
            processData: false,
            dataType: 'text', 
            success: function(response) {

                var receiptFile = new XMLHttpRequest();
                receiptFile.open('PATCH', 'http:/example.com:3000/uploads/' + uploadId, false);
                receiptFile.setRequestHeader("Content-type","application/json");
                receiptFile.send('{"fileURL": "' + fileURL + '"}');

            }
    });

}

(I pass the file to this function onChange from a <input type="file" onchange="uploadReceipt(this)">)

DanielJackson-Oslo avatar Jun 18 '17 11:06 DanielJackson-Oslo

I don't know about this issue... I do upload files to json-server and it works fine and even gives me progress while uploading. It would be cool to throttle the upload since it is really fast on localhost but this can be done in Chrome for example.

If you want to save the file, dude that is not what a fake-api is supposed to do. But if you really want, you can use node.js of course and do everything that comes into your mind:

server.all('/myRoute', (req, res) => {
   // Save the image or do whatever you want ...
});

I think this issue should be closed.

MickL avatar Feb 13 '19 14:02 MickL

@MickL and how do you did it? I wont load by binary string, I'm post with 'Content-Type': 'application/x-www-form-urlencoded' and inside my loadfile.js middleware express cant define req.files This case looks like a solution but It needs configuring server.js file - command API not enough for upload proccessing. So issue is open - that's right

WebKieth avatar Nov 06 '19 14:11 WebKieth

What do you mean bei loadfile and middleware and express? This is just a fake api, you create a route and you can send data to it. This data can also be file data. If you want to save the file just save it like my example. This works out of the box. Issue can be closed.

MickL avatar Nov 06 '19 14:11 MickL

@MickL seems like you read my comment inattentively.

server.use((req, res, next) => {
    if (req.path === '/loadfile') {
        console.log(req.files) // undefined
    } else {
        next()
    }
 })

And when I added connect-busboy module for load streaming json-server stops responsing for all requests. File uploading don't work.

WebKieth avatar Nov 06 '19 14:11 WebKieth

It would be req.body.files and if it is undefined you didnt send any.

MickL avatar Nov 06 '19 15:11 MickL

@MickL i tried req.body.files - still undefined. My file was sended inside formData object - I sure about it. I open network tab inside devtools and see file: (binary) under Form Data title. And multipart/form-data setted. Request looks right.

So I will try to send it to clean express with connect-busboy. I think it will be work

WebKieth avatar Nov 06 '19 15:11 WebKieth

file is not files and this is not a support forum too. I guarantee you you can put files in the body, get progress while sending the request and on json-server side the body will not be undefined. Note that you have to use bodyParser as seen in the readme.

MickL avatar Nov 06 '19 15:11 MickL

@MickL Of course this is support forum. Issue tab was created for helps coders solve their problems with some software by fix this software. json-server cant upload file out of the box and this is issue of json-server. I don't need you to solve my problems - and I didnt ask you for it. So dont tell me about it - by the way, you are shitty support. I fix it on way which I saw - just migrating on express + busboy.

app.post('/loadfile', (req, res) => {
    let fstream;
    req.pipe(req.busboy);
    req.busboy.on('file', function (fieldname, file, filename) {
        console.log("Uploading: " + filename); 
        fstream = fs.createWriteStream(__dirname + '/uploaded/' + filename);
        file.pipe(fstream);
        fstream.on('close', function () {
            res.send({url: __dirname + '/uploaded/' + filename})
        });
    });
 })

I think it would be simple to add this middleware out of the box. But now issue isnt solved and then shuldnt be closed

WebKieth avatar Nov 06 '19 15:11 WebKieth

You can send anything you want to the server and receive anything that has been sent in the request body. You even get progress. How is this not supported?

And btw an issue tracker is for bugs and issues not for support requests.

MickL avatar Nov 06 '19 16:11 MickL

You can send anything you want to the server

You wrong. Cause you didnt follow link which I put inside my first comment. json-server use body-parser. Note from their readme

This does not handle multipart bodies, due to their complex and typically large nature

As I say - you are bad support =)

WebKieth avatar Nov 06 '19 16:11 WebKieth

I am not any kind of support. I am just saying sending files works out of the box i implemented it myself. Ofcourse you have to send the files urlencoded in the body and not as multipart!

MickL avatar Nov 06 '19 16:11 MickL

@MickL what means your 'Ofcourse'? Maybe for you this is 'ofcource', but not for me or anybody else. It have to be written in docs

WebKieth avatar Nov 06 '19 16:11 WebKieth

sending binaries is allowed only with multipart/form-data

json-server under the hood is using express.js knowing that we can use multer to handling uploads.


// server.js
const jsonServer = require('json-server');
const path = require('path');
var multer  = require('multer');
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, 'public/uploads'));
  },
  filename: function (req, file, cb) {
    cb(null, file.fieldname + '-' + Date.now());
  }
})


var upload = multer({ storage })

const server = jsonServer.create();
const router = jsonServer.router(path.join(__dirname, 'db.json'));
const middlewares = jsonServer.defaults();

server.use(middlewares);
server.use(upload.any());
server.use(router)
server.listen(3000, () => {
  console.log('JSON Server is running')
})

ValeriyDP avatar Feb 05 '20 08:02 ValeriyDP

I find another produce just like json-server without so many apis : aok.js
and it support upload file , or csv for table

zhangweiHello avatar Jul 09 '20 07:07 zhangweiHello

so you created a fileserver outside of this project on a separate machine? that was not exactly I was looking for. Or did I misunderstand you?

or use an api that lets you upload images and store the images link in the json server :). try Imgur api, is quite nice, easy and free

stefantanasa avatar Jun 06 '22 20:06 stefantanasa