graphql-upload with cloudinary

Comments

20 comments

  • Avatar
    matthew

    Hendry, you dont need the createReadStream() call because the stream that is sent from the apollo client is already a readable stream, you should be able to call stream.pipe(upload_stream) and have it work

    1
    Comment actions Permalink
  • Avatar
    Guillaume

    Thank you for the code ! It has been very useful for me. This is the one I did (it might have some mistakes, as I am a newbie but is working), inspired from Hendry and Jayden Seric : 

    with authentication, for single and multiple uploads, requires npm package promises-all : 

     

    import promisesAll from 'promises-all';
    const processUpload= async upload => {
    const {stream }= await upload;

    const cloudinary = require('cloudinary');
    cloudinary.config(
    {
    cloud_name: 'your-cloud-name',
    api_key: 'your-api-key',
    api_secret: 'your-api-secret'
    }
    );

    let resultUrl = '', resultSecureUrl = '';
    const cloudinaryUpload = async ({stream}) => {
    try {
    await new Promise((resolve, reject) => {
    const streamLoad = cloudinary.v2.uploader.upload_stream(function (error, result) {
    if (result) {
    resultUrl = result.secure_url;
    resultSecureUrl = result.secure_url;
    resolve(resultUrl)
    } else {
    reject(error);
    }
    });

    stream.pipe(streamLoad);
    });
    }
    catch (err) {
    throw new Error(`Failed to upload profile picture ! Err:${err.message}`);
    }
    };

    await cloudinaryUpload({stream});
    return(resultUrl)

    };

    Mutation : {

    async singleFileUpload(parent, {file}) {

    return(processUpload(file))

    },
    async multipleFileUpload(parent, {files}) {
    const {resolve, reject} = await promisesAll.all(
    files.map(processUpload)
    );

    if (reject.length) {
    reject.forEach(
    ({name, message}) => {
    console.error(`${name}:${message}`)
    }
    )
    }
    return resolve;
    },


    }

     

     

    1
    Comment actions Permalink
  • Avatar
    Raya Straus

    Hi Hendry,

    Please take a look at the upload stream examples on our repo-https://github.com/cloudinary/cloudinary_npm/blob/bf7103aac2714002305566d05a53ded4cdcafbca/samples/basic/basic.js#L32

    var upload_stream= cloudinary.v2.uploader.upload_stream({tags: 'basic_sample'},function(err,image) {
    console.log('here');
    console.log("** Stream Upload");
    //if (err){ console.warn(err);}
    console.log("* Same image, uploaded via stream");
    console.log("* "+image.public_id);
    console.log("* "+image.url);
    });
    var file_reader = fs.createReadStream('<local_file_name>').pipe(upload_stream);

    You'll then get the URL in the resonse as seen above 

     

     

    0
    Comment actions Permalink
  • Avatar
    Hendry

    Hi Raya,

    thanks for your pointers. I am still unable to get it to work. I am not very familiar with how stream works. I plugged in my stream object at fs.createReadStream. is that correct? or should I insert my stream in another portion of the code? Tq

    Below is my mutation codes

    import * as fs from "fs";
    import cloudinary from "cloudinary";
     
    Mutation: {
    uploadPicture:async (_, { file }) => {
    const { stream } =await file;
    console.log("stream ", stream);

    try {
    //TODO upload to cloudinary
    const upload_stream=cloudinary.uploader.upload_stream(
    { tags: "sample" }, 
    function(err:any, image:any) {
    console.log();
    console.log("** Stream Upload");
    if (err) {
    console.warn(err);
    }
    console.log("* Same image, uploaded via stream");
    console.log("* "+image.public_id);
    console.log("* "+image.url);
    }
    );
    const file_reader=fs.createReadStream(stream).pipe(upload_stream);
    console.log(file_reader);
     
    } catch (error) {
    throwerror;
    }
    returntrue;
    },
    0
    Comment actions Permalink
  • Avatar
    Raya Straus

    Are you seeing any errors? Also, it looks like you're missing the v2 from your request. Can you please try adding it? cloudinary.v2.uploader.upload_stream...

    0
    Comment actions Permalink
  • Avatar
    Hendry

    I tried adding v2 but still can't work. I don't see any error messages on console. I m not familiar with working with streams. Is it correct that I pass the stream object which I get from graphql-upload directly to the createReadStream and that is supposed to work?

    const file_reader=fs.createReadStream(stream).pipe(upload_stream);

    0
    Comment actions Permalink
  • Avatar
    Hendry

    Thanks Matthew! It worked. Below are my codes for those who are using graphql-upload with cloudinary

    const cloudinaryUpload = async ({ stream }: any): Promise<any> => {
    const streamLoad = cloudinary.v2.uploader.upload_stream(function(
    error:any,
    result:any
    ) {
    if (result) {
    console.log("result ", result);
    } else {
    console.log("error ", error);
    }
    });

    stream.pipe(streamLoad);

    return`Test`;
    };

    export const processCloudinaryUpload = async (upload: any) => {
     
    const { stream } =await upload;

    await cloudinaryUpload({ stream });

     
    };
    0
    Comment actions Permalink
  • Avatar
    Shirly Manor

    Thank you for pointing out Matthew and Hendry for your update!

    0
    Comment actions Permalink
  • Avatar
    Hendry

    Thanks Guillaume!  your codes help in getting a url response from the server. tq :)

    0
    Comment actions Permalink
  • Avatar
    Duke Osain
    const cloudinary = require("cloudinary").v2;

     

    Hello, am having  similar issue, i tried to follow the example above but is still not work.

    Am using apollo graphql to pass body of post and file upload, at the backend i console.log(file) and it shows the result below but i console.log(stream) it gives undefile . am trying to store it cloudinary before storing the link at MongoDb, but is the storing of the file at cloudinary  working. 

    Am having this error " 

    • TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type undefined"

     

    The is the  mutation 

    mutation ($body: String!, $file : Upload){
    createPost(body: $body, file: $file){
    id body createdAt username

    likes{
    id createdAt username
    }
    likeCount
    comments{
    id body createdAt username

    }
     
    commentCount
    }
    }
    `;
     
    Thanks for your help
    0
    Comment actions Permalink
  • Avatar
    Shirly Manor

    Hi Duke,

    As Matthew said you don't need the createReadStream()

    Can you try again with the previous sample code:

    ```

    try {
    await new Promise((resolve, reject) => {
    const streamLoad = cloudinary.v2.uploader.upload_stream(function (error, result) {
    if (result) {
    resultUrl = result.secure_url;
    resultSecureUrl = result.secure_url;
    resolve(resultUrl)
    } else {
    reject(error);
    }
    });

    stream.pipe(streamLoad);
    });
    }

    Thanks,

    0
    Comment actions Permalink
  • Avatar
    Duke Osain

    Thanks Shirly Manor for your reply 

    I have tried it but it gives an error "  ReferenceError: stream is not defined "

    I also console.log(stream) but it gives undefined , is stream supposed to be undefined ?.

    but if console.log(file)  it give the result as shown 

    Server running at http://localhost:5000/
    Promise {
    { filename: 'Screenshot 2019-07-29 at 12.59.53.png',
    mimetype: 'image/png',
    encoding: '7bit',
    createReadStream: [Function: createReadStream] } }

    0
    Comment actions Permalink
  • Avatar
    Shirly Manor

    Hi Duke,

    Did you initiate the stream?

    e.g.:

     

    ```

    const { stream } =await upload; 

    ```

    0
    Comment actions Permalink
  • Avatar
    Duke Osain

    Thanks 

    It works now but i am having this message about depreciation 

    "  (node:3979) DeprecationWarning: File upload property ‘stream’ is deprecated. Use ‘createReadStream()’ instead "

    since is depreciated will stop working ?

    if i want to use this then var file_reader = fs.createReadStream('<local_file_name>').pipe(upload_stream);, 

    what is  the  '<local_file_name>'  , i tried to use the finename but is not working 

    0
    Comment actions Permalink
  • Avatar
    Shirly Manor

    Hi Duke,

     

    When I google it, I found that the filename is the local directory and the file name. e.g, `dev/test.txt`.

    You can read about it here:

    https://nodejs.org/en/knowledge/advanced/streams/how-to-use-fs-create-read-stream/

    Thanks,

    0
    Comment actions Permalink
  • Avatar
    Carolina de la Fuente

    Thanks to everyone on this thread. Also noting that this only works with images by default, if you try to upload a video, it will give you the error: 'Invalid image file'.

    To upload videos, add { resource_type: 'video' } as the first argument of your uploader.upload_stream() method.

    0
    Comment actions Permalink
  • Avatar
    Ido

    Hi Carolina,

    Yes, the default value for uploading for the resource_type parameter is image, so you must set the resource_type parameter and set it to "video" when uploading videos.

    You can read more about that here:

    https://cloudinary.com/documentation/upload_images#uploading_videos

    0
    Comment actions Permalink
  • Avatar
    lucas teisseire

    Hi there, i have same issues i cant figure it out so this is my mutation =======>

    ------ MUTATION -------

    ```

    t.field('uploadSupportAttachment', {
    type: 'FileUpload',
    args: {
    file: arg({ type:'Upload' }),
    },
    resolve: async (_, { file }, ctx) => {
    const result = await uploadFile(file)
    return file
    },
    })```

    this is my utils ======>

    ----- UTILS ----- 

    ```export const uploadFile = async (file: any) => {
    cloudinary.v2.config({
    cloud_name: '////',
    api_key: '////',
    api_secret: '////',
    })
    const { createReadStream, filename } = await file
    const fileStream = createReadStream()

    const streamLoad = cloudinary.v2.uploader.upload_stream(
    { timeout: 120000 },
    function (
    error: any,
    result: any
    ) {
    if (result) {
    console.log('result ', result)
    } else {
    console.log('error ', error)
    }
    })
    fileStream.pipe(streamLoad)
    return''
    }```
     
    what i receive from front is ====> 
     
    Promise {
    {
    filename: 'drilldown.png',
    mimetype: 'image/png',
    encoding: '7bit',
    createReadStream: [Function: createReadStream]
    }
    }
     
    i cant stop to have this ====> error {
    message: 'Server returned unexpected status code - 504',
    http_code: 504,
    name: 'UnexpectedResponse'
    }
     
    someone can help ??? thanks in advance
    0
    Comment actions Permalink
  • Avatar
    Shirly Manor

    Hi Lucas,

    You can read more on how to use the upload_stream here:

    https://support.cloudinary.com/hc/en-us/community/posts/360007581379-Correct-way-of-uploading-from-buffer-

    0
    Comment actions Permalink
  • Avatar
    Sameer

    If you're using apollo-upload-client on the client-side, the easiest way is to use the createReadStream function that the uploaded image resolves to, and pipe that stream directly to Cloudinary.

    const { createReadStream, filename, mimetype, encoding } = await image;
     
    try {
    result = awaitnewPromise((resolve, reject) => {
    createReadStream().pipe(
    cloudinary.uploader.upload_stream((error, result) => {
    if (error) {
    console.log(error);
    }

    console.log('image uploaded');
    })
    );
    });
    } catch (error) {
    console.log(error);
    }
    0
    Comment actions Permalink

Please sign in to leave a comment.