Code Monkey home page Code Monkey logo

syncano-node's Introduction

Syncano Toolkit

  • CLI - Manage Syncano Instances, install and deploy Syncano Sockets
  • Client Library - Interact with Syncano Sockets via JavaScript
  • Core Library - Communicate with Syncano Core Services
  • Test Library - Run test suites on Syncano Sockets
  • Validate Library - Validate requests to Syncano Sockets

Documentation

Community

Issues

Found a bug? Let us know so we can take care of it.

Contributing

Please see our contributing.md

License

MIT. See license.

syncano-node's People

Contributors

23doors avatar adamwardecki avatar danielruf avatar eshaibu avatar hzub avatar idered avatar jakubkornafel avatar jonny22094 avatar ksyhoo avatar maciejkorsan avatar mattlsp avatar mkucharz avatar olapinska avatar pbres avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

syncano-node's Issues

Fields method based on schema definition

endpoints:
  create-wish:
    parameters:
      title:
        type: string
      description:
        type: text
    response:
      success:
        exit_code: 200
        parameters:
          title:
            type: text
const wish = {
  title: 'Lorem ipsum',
  description: 'Dolor sit amet',
  uuid: '12ji21d-0ek=2-em12ednfm'
}

response.success(wish)

response.success undercover should use fields method and only return properties defined in the schema. In this case {title: 'Lorem ipsum'} should be returned.

// cc @mkucharz

Method: increment

data.posts.increment('votes') // Increment by 1
data.posts.where('id', 10).increment('votes', 13) // Increment by 13

Method: sum

data.comments
  .sum('likes')
  .then(numberOfLikes => {})

Method: whereNotBetween

// Get posts with number of votes not between 50 and 100
data.posts
  .whereNotBetween('votes', 50, 100)
  .list()

Method: orWhere

// Get posts with id lower than 100 and posts with id higher than 200
data.posts
	.where('id', 'lt', 100)
	.orWhere('id', 'gt', 200)
	.list()

Method: decrement

data.posts.decrement('votes') // Decrement by 1
data.posts.where('id', 10).decrement('votes', 13) // Decrement by 13

Invalid http resoponse on error.

Expected behaviour

HTTP/1.1 500 Internal Server Error
Server: nginx
Content-Type: text/plain; charset=utf-8
Content-Length: 692
Connection: keep-alive
Keep-Alive: timeout=20
Date: Thu, 30 Nov 2017 10:01:38 GMT

{"id":3,"executed_at":"2017-11-30T10:01:38.029762Z","status":"failure","duration":10,"result":{"stdout":"","stderr":"{ module.js:471\n    throw err;\n    ^\n\nError: Cannot find module 'bar'\n    at Function.Module._resolveFilename (module.js:469:15)\n    at Function.Module._load (module.js:417:25)\n    at Module.require (module.js:497:17)\n    at require (internal/module.js:20:19)\n    at fail-case.js:11:12\n    at ContextifyScript.Script.runInContext (vm.js:35:29)\n    at processScript (/app/wrapper/node.js:133:22)\n    at Socket.\u003canonymous\u003e (/app/wrapper/node.js:191:5)\n    at emitOne (events.js:96:13)\n    at Socket.emit (events.js:188:7) code: 'MODULE_NOT_FOUND' }\n"}}

Expected 500 (or better suited one) http response code.

Actual behaviour

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/plain; charset=utf-8
Content-Length: 692
Connection: keep-alive
Keep-Alive: timeout=20
Date: Thu, 30 Nov 2017 10:01:38 GMT

{"id":3,"executed_at":"2017-11-30T10:01:38.029762Z","status":"failure","duration":10,"result":{"stdout":"","stderr":"{ module.js:471\n    throw err;\n    ^\n\nError: Cannot find module 'bar'\n    at Function.Module._resolveFilename (module.js:469:15)\n    at Function.Module._load (module.js:417:25)\n    at Module.require (module.js:497:17)\n    at require (internal/module.js:20:19)\n    at fail-case.js:11:12\n    at ContextifyScript.Script.runInContext (vm.js:35:29)\n    at processScript (/app/wrapper/node.js:133:22)\n    at Socket.\u003canonymous\u003e (/app/wrapper/node.js:191:5)\n    at emitOne (events.js:96:13)\n    at Socket.emit (events.js:188:7) code: 'MODULE_NOT_FOUND' }\n"}}

Steps to reproduce

socket.yml

name: fail-case
description: Description of fail-case
version: 0.0.1

endpoints:
  fail-case:
    file: fail-case.js
    description: Bad script
    parameters:
    response:

src/fail-case.js

import Server from 'syncano-server';
import foo from 'bar';

export default async ctx => {
  const {response} = Server(ctx);
  return response.json({hello: 'world'});
};

package.json

{
  "license": "MIT",
  "dependencies": {
    "syncano-server": "beta"
  },
  "devDependencies": {
    "eslint": "^4.12.1"
  }
}

Details

npx s version

0.53.0

Obviously script has a bad module called 'bar'. The script execution will fail because of that. I would expect http response contain an error code. Maybe 500 Internal Server Error?

Method: avg

data.comments
  .avg('likes')
  .then(averangeNumberOfLikes=> {})

Method: whereNotIn

// Get posts with ids not in given array
data.posts
  .whereNotIn('id', [20, 30,132])
  .list()

Method: whereYear

// Get posts created in 2017
data.posts
  .whereYear('created_at', 2017)
  .list()

Authentication error on creation of project doesn't stop the process

syncano-cli init
 
    You have to be logged in to initialize a new project! 
 
    Welcome to Syncano (syncano.io) 
    Please login or create an account by entering your email and password: 
 
?         Your e-mail [email protected]
?         Password *********
    Authentication error! ๐Ÿ˜ข 
 
    Invalid password. 
 
    New project? Exciting! ๐ŸŽ‰ 
 
?   Choose template for your project     hello - Hello World template (recommended)
 
    Creating Syncano Instance... You do not have permission to perform this action

Method: min

const minimalNumberOfLikes = await data.comments.min('likes')

Invalid response when body is empty

Expected behaviour

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/plain; charset=utf-8
Content-Length: 122
Connection: keep-alive
Keep-Alive: timeout=20
Date: Wed, 06 Dec 2017 13:13:17 GMT

When response is returned and is empty, it should stay empty.

Actual behaviour

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/plain; charset=utf-8
Content-Length: 122
Connection: keep-alive
Keep-Alive: timeout=20
Date: Wed, 06 Dec 2017 13:13:17 GMT

{"id":27,"executed_at":"2017-12-06T13:13:17.344436Z","status":"success","duration":810,"result":{"stdout":"","stderr":""}}

Steps to reproduce

socket.yml

name: fail-case
description: Description of fail-case
version: 0.0.1

endpoints:
  fail-case:
    file: fail-case.js
    description: Empty response
    parameters:
    response:

src/fail-case.js

import Server from 'syncano-server';

export default async ctx => {
  const {response} = Server(ctx);
  return response('', 200, 'text/plain', {});
};

package.json

{
  "license": "MIT",
  "dependencies": {
    "syncano-server": "beta"
  },
  "devDependencies": {
    "eslint": "^4.12.1"
  }
}

Details

npx s version

0.53.0

When script returns an empty response, it replaces it with script execution info. Sometimes empty response is an expected behaviour. It can be useful for application/octet-stream and text/plain content-type responses, but it also fails at empty application/json.

Syncano-cli call throws error on grouped endpoint

s call throws error message on grouped endpoint (e.g s call stripe/charge/createcharges/) when run on command line, but, endpoint works fine in postman and browers.

In defining the grouped endpoint, the following steps were taken:

  • Create a charge folder in src folder
  • create charge related script file (e.g. createCharges.js, retrieveCharges.js, e.t.c.) in src/charge folder
  • Define endpoint in socket.yml file as shown below (N/B: without the file path):

screen shot 2017-12-08 at 7 16 10 pm

Error message:

No such endpoint on the server! Make sure you have synced your socket.

Function: redirect

import {redirect} from 'syncano-server'

redirect('https://example.com')

Method: whereDay

// Get posts where created at day is 22
data.posts
  .whereDay('created_at', 22)
  .list()

hosting sync fails on pure Windows

When calling s hosting sync or s hosting add on Windows it returns (for chat-app):

Error while syncing (creating) syncano_logo_white.svg
Error while syncing (creating) syncano-client.min.js
TypeError: Cannot read property 'size' of undefined

Further debugging led me to an issue with Windows path separator, and this code in hosting.js getFilesToUpload function allowed me to fix it temporarily on my local machine:

const fileToUpdate = _lodash2.default.find(remoteFiles, { path: localHostingFilePath.replace('\\','/') });
const payload = { file: _session2.default.connection.file(file.localPath), path: localHostingFilePath.replace('\\','/') };

Resetting instance

It would be nice to have a chance to reset instance instead of deleting/creating one. By resetting i mean deleting everything inside and cleaning up all the settings.

Method: whereIn

// Get posts with ids in given aray
data.posts
  .whereIn('id', [20, 30,132])
  .list()

Method: whereBetween

// Get posts with number of votes between 50 and 100
data.posts
  .whereBetween('votes', 50, 100)
  .list()

Method: whereNull

// Get not updated posts
data.posts
  .whereNull('updated_at')
  .list()

Method: whereDate

// Get posts with given date
data.posts
  .whereDate('created_at', '2017-06-22')
  .list()

Method: max

const maxNumberOfLikes = await data.comments.max('likes')

Method: computed

Computed method would be run for each element returned from list(). Result of computed would be assigned to each of returned objects.

data.profiles
  .computed(profile=> ({
    full_name: `${profile.first_name} ${profile.last_name}`
  }))
  .list()

/cc @mkucharz

Users object in core retaining query.

Expected behaviour

Each chained call to users.where(/something/).doSomething() to be standalone separate query.

Actual behaviour

users property on server object is not an instance of Proxy, unlike data property, so each query on Server(ctx).users retains old query.

Steps to reproduce

socket.yml

name: users-fail-case
description: Description of users-fail-case
version: 0.0.1
endpoints:
  fail-case:
    file: fail.js
    description: abc
    parameters:

src/fail-case.js

import Server from 'syncano-server';

export default async ctx => {
  const {logger, response, users} = Server(ctx);
  const {debug} = logger(ctx.meta.executor);
  let user = await users.updateOrCreate({
    username: 'john_doe',
    password: '|*455|/\\|0|2|)'
  });
  debug(user);
  try {
    await users.delete(user.id);
  } catch (e) {
    debug(e.response);
    return response.json({message: e.message}, 400);
  }
  return response.json({});
};

package.json

{
  "license": "MIT",
  "dependencies": {
    "syncano-server": "beta"
  },
  "devDependencies": {
    "eslint": "^4.12.1"
  }
}

Details

npx s version

0.53.0

Users is not a proxy, so query is retained.

Logs from calls:

updateOrCreate
                { 
                  "username": "john_doe", 
                  "channel_room": null, 
                  "links": { 
                    "self": "/v2/instances/misty-snowflake-6430/users/3/", 
                    "groups": "/v2/instances/misty-snowflake-6430/users/3/groups/", 
                    "reset-key": "/v2/instances/misty-snowflake-6430/users/3/reset_key/" 
                  }, 
                  "user_key": "fb5cc328267b00405bc5c4fd1cac9208fa6f13aa", 
                  "created_at": "2017-12-08T15:50:18.343834Z", 
                  "updated_at": "2017-12-08T15:50:18.343849Z", 
                  "acl": { 
                    "users": { 
                      "3": [ 
                        "read", 
                        "write" 
                      ] 
                    } 
                  }, 
                  "groups": [], 
                  "id": 3, 
                  "channel": null, 
                  "revision": 1 
                } 
delete
                { 
                  "data": { 
                    "query": "Invalid field name defined: \"password\"." 
                  }, 
                  "body": { 
                    "_readableState": { 
                      "objectMode": false, 
                      "highWaterMark": 16384, 
                      "buffer": { 
                        "head": null, 
                        "tail": null, 
                        "length": 0 
                      }, 
                      "length": 0, 
                      "pipes": null, 
                      "pipesCount": 0, 
                      "flowing": true, 
                      "ended": true, 
                      "endEmitted": true, 
                      "reading": false, 
                      "sync": false, 
                      "needReadable": false, 
                      "emittedReadable": false, 
                      "readableListening": false, 
                      "resumeScheduled": false, 
                      "defaultEncoding": "utf8", 
                      "ranOut": false, 
                      "awaitDrain": 0, 
                      "readingMore": false, 
                      "decoder": null, 
                      "encoding": null 
                    }, 
                    "readable": false, 
                    "domain": null, 
                    "_events": {}, 
                    "_eventsCount": 3, 
                    "_writableState": { 
                      "objectMode": false, 
                      "highWaterMark": 16384, 
                      "needDrain": false, 
                      "ending": true, 
                      "ended": true, 
                      "finished": true, 
                      "decodeStrings": true, 
                      "defaultEncoding": "utf8", 
                      "length": 0, 
                      "writing": false, 
                      "corked": 0, 
                      "sync": false, 
                      "bufferProcessing": false, 
                      "writecb": null, 
                      "writelen": 0, 
                      "bufferedRequest": null, 
                      "lastBufferedRequest": null, 
                      "pendingcb": 0, 
                      "prefinished": true, 
                      "errorEmitted": false, 
                      "bufferedRequestCount": 0, 
                      "corkedRequestsFree": { 
                        "next": null, 
                        "entry": null 
                      } 
                    }, 
                    "writable": false, 
                    "allowHalfOpen": true, 
                    "_transformState": { 
                      "needTransform": false, 
                      "transforming": false, 
                      "writecb": null, 
                      "writechunk": null, 
                      "writeencoding": "buffer" 
                    } 
                  }, 
                  "size": 0, 
                  "timeout": 0, 
                  "url": "https://api.syncano.io/v2/instances/misty-snowflake-6430/users/3/?query=%7B%22username%22%3A%7B%22_eq%22%3A%22john_doe%22%7D%2C%22password%22%3A%7B%22_eq%22%3A%22%7C*455%7C%2F%5C%5C%7C0%7C2%7C)%22%7D%7D&page_size=1", 
                  "status": 400, 
                  "statusText": "Bad Request", 
                  "headers": {} 
                }

Beta syncano-cli init - error no such api key

I've installed syncano-cli@beta and wanted to start a new project.

 syncano-cli init
 
    New project? Exciting! ๐ŸŽ‰ 
 
?   Choose template for your project     hello - Hello World template (recommend
ed)
 
    Creating Syncano Instance... No such API Key. 

Method: whereMonth

// Get posts created in March
data.posts
  .whereMonth('created_at', 3)
  .list()

Null where not possible

data.model.where('something',null)

is not possible right now. It should convert where to isnull

.uniqe() feature for listing data

For example: .uniqe('name') will take only first unique record (by 'name' field)

Hmm, maybe this should be part of collections feature?

let sockets = data.sockets.list().then(sockets => 
  sockets.unique('name').sortBy('name')
)

data.sockets.list().then(sockets => 
  sockets.filter(item => item.name === 'malgun').update({name: 'mailgun'})
)

https://github.com/ecrmnn/collect.js

Models

models:
  post:
    hidden: updated_at, id, $syncano
    computed:
      full_name: `${first_name} ${last_name}`
    scope:
      published:
        - column: published
          value: true
      unpublished:
        - column: published
          value: false
      fromLastWeek:
        - column: published
          value: true
        - column: created_at
          is: gte
          value: new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000)

models.post.hidden
Define columns hidden in results. $syncano means "hide all syncano columns"

models.post.scope
Define named queries

data.post.published().list()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.