{"__v":14,"_id":"57617063f4b46b1700861274","category":{"__v":1,"_id":"56b098da8f7a4f0d0029dd10","pages":["56b0c05c0f5f980d0059fb91"],"project":"54774d9af3736008009e9e0e","version":"56a0bd9e3697d80d002ac5e7","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-02-02T11:54:02.535Z","from_sync":false,"order":11,"slug":"syncano-basics","title":"Syncano Basics"},"parentDoc":null,"project":"54774d9af3736008009e9e0e","user":"54774c47f3736008009e9e0c","version":{"__v":20,"_id":"56a0bd9e3697d80d002ac5e7","project":"54774d9af3736008009e9e0e","createdAt":"2016-01-21T11:14:38.131Z","releaseDate":"2016-01-21T11:14:38.131Z","categories":["56a0bd9f3697d80d002ac5e8","56a0bd9f3697d80d002ac5e9","56a0bd9f3697d80d002ac5ea","56a0bd9f3697d80d002ac5eb","56b098a43a5b810d00745e3f","56b098da8f7a4f0d0029dd10","56d5a8ecf612b80b00fb69cd","570989853ab43c0e0072b2d6","571006aa10300c0e007f6133","5735a52431a73b1700887ca0","5744b0529e045c0e00b7a7a2","5744b1d0b56d431700d8a4fb","5744b1fb55d65a0e00b436e1","5744b218f9c7411700ce560e","5744b220f9c7411700ce560f","5744b2259e045c0e00b7a7a7","5744b22cf8b79f0e00de6a2d","5744b23155d65a0e00b436e4","5744b242c758290e00fbc235","5744b2569e045c0e00b7a7a8","5756a3f2bb92962900dafe3d","57ee23e81e42900e0014a42f","581c822c98676e0f00d240ef"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"Sockets","version_clean":"1.1.0","version":"1.1"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-06-15T15:12:35.124Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"## Chapter Contents:\n1. [Overview](#overview)\n2. [Adding a new Script](#adding-a-new-script)\n3. [Runtimes and libraries](#runtimes-and-libraries)\n4. [Running a Script](#running-script)\n5. [Script Example](#script-code-example)\n6. [Scripts data dictionaries: ARGS, CONFIG, Global CONFIG and META](#scripts-data-dictionaries-args-config-global-confi)\n7. [Custom Script Timeouts](#section-script-timeouts-and-custom-timeout)\n8. [Handling files in Scripts](#handling-files-in-scripts)\n9. [Summary](#summary)\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Overview\"\n}\n[/block]\nA [Script](glossary#section-snippet-script) is an object that contains code that can be run on Syncano's servers. \n\n### What can be accomplished with a Script\n\nA Script is a very powerful tool. Just like with code, you can do a lot with it. Additionally, Syncano gives you many ways to run Scripts. This is where you can get creative. \n\nWith a Script you can:\n\n- compute tasks that are too expensive to compute on mobile/frontend side.\n- create your own logic in the cloud that can be accessed by an API built on Script Endpoints (complex filtering, composing multiple objects)\n- handle events on Syncano with Trigger Sockets\n- trigger jobs in the cloud with the API\n- run scheduled jobs - cloud cron\n- build your own integrations between services with Scripts powered Script Endpoints\n- create public Script Endpoints available for people that know the link\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Note on pricing\",\n  \"body\": \"Scripts pricing is based on total execution time. So, in terms of billing, 30 Script runs that took 1 second each are equal to one Script run that took 30 seconds. Builder plan allows for 20.000 (twenty thousand) Script seconds per month.\"\n}\n[/block]\n### Script Properties\n\nSo what exactly is this Script? This is how a Script object can look like:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"config\\\": {}, \\n  \\\"id\\\": 1, \\n  \\\"runtime_name\\\": \\\"python\\\", \\n  \\\"label\\\": \\\"here\\\", \\n  \\\"description\\\": \\\"there\\\", \\n  \\\"source\\\": \\\"print('ello')\\\", \\n  \\\"created_at\\\": \\\"2015-01-28T14:02:38.408864Z\\\", \\n  \\\"updated_at\\\": \\\"2015-01-28T14:02:38.408920Z\\\", \\n  \\\"links\\\": {\\n      \\\"traces\\\": \\\"/v1.1/instances/syncano/snippets/scripts/1/traces/\\\", \\n      \\\"self\\\": \\\"/v1.1/instances/syncano/snippets/scripts/1/\\\", \\n      \\\"run\\\": \\\"/v1.1/instances/syncano/snippets/scripts/1/run/\\\", \\n      \\\"runtimes\\\": \\\"/v1.1/instances/syncano/snippets/scripts/runtimes/\\\"\\n  }\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nAnd here's an overview of the unique properties that Script has:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Property\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"`runtime_name`\",\n    \"0-1\": \"The `runtime environment` that the Script will run in (i.e. Ruby, Python, NodeJS, Golang, Swift and PHP). Every language is supported by a different runtime environment. The runtime environment also supports several libraries for each language. For example: The Python runtime has a `requests` library.\",\n    \"1-0\": \"`source`\",\n    \"1-1\": \"A piece of code that will run when the Script is executed.\",\n    \"2-0\": \"`label`\",\n    \"2-1\": \"Label of the Script\",\n    \"3-0\": \"`description`\",\n    \"3-1\": \"Script description\",\n    \"4-1\": \"A very useful field that can be used to store your confidential data such as APIKEYS or any other configurable variables.\",\n    \"4-0\": \"`config`\"\n  },\n  \"cols\": 2,\n  \"rows\": 5\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"For advanced users:\",\n  \"body\": \"Runtimes are described by Dockerfiles, you can find all of them on our Github account:\\n- https://github.com/Syncano/python-codebox\\n- https://github.com/Syncano/golang-codebox\\n- https://github.com/Syncano/nodejs-codebox\\n- https://github.com/Syncano/ruby-codebox\\n- https://github.com/syncano/swift-codebox\\n- https://github.com/syncano/php-codebox\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Adding a new Script\"\n}\n[/block]\nThe easiest way to add a new Script, is with help of the [Dashboard](https://dashboard.syncano.io). \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/outHfAyPQmC37wwuQddD_Add_codebox_01.png\",\n        \"Add_codebox_01.png\",\n        \"1279\",\n        \"654\",\n        \"#234473\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/e3fMoPDSRIqeLNqMnlIF_Add_codebox_02.png\",\n        \"Add_codebox_02.png\",\n        \"1279\",\n        \"655\",\n        \"#6c84a4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ihQC7RZtSlWF9DIoNM7g_Add_codebox_03.png\",\n        \"Add_codebox_03.png\",\n        \"1279\",\n        \"653\",\n        \"#25426f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Runtimes and libraries\"\n}\n[/block]\nIt is possible to write your code in one of few selected runtimes.\n\nYou can always find most up-to-date list with supported languages using our API. \nTo do so, make a GET request on an `/instances/:instance_name/scripts/snippets/runtimes/` endpoint, e.g.:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X GET \\\\\\n-H \\\"X-API-KEY: <ACCOUNT_KEY>\\\" \\\\\\n\\\"https://api.syncano.io/v1.1/instances/<instance_name>/scripts/snippets/runtimes/\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nAs of October 2016, we support following programming languages/runtimes:\n\n- NodeJS\n- Python\n- Swift\n- Golang\n- PHP\n- Ruby\n\nFor some of the languages, we support adding libraries/packages, from popular repositories/package managers. \nCurrently it is not possible to define packages available in a Script using our Dashboard. Instead, to request a new library: \n\n- Write to us at [support:::at:::syncano.com](mailto:support@syncano.com). Let us know which library you'd like to have added for which language;\n- or make a pull request to our repository (and change a file with list of available libraries)\n\nYou can find listing of libraries available in a Script on our GitHub:\n\n- Python 2.7 - https://github.com/Syncano/python-codebox/blob/master/python/files/requirements.txt\n- Python 3 - https://github.com/Syncano/python-codebox/blob/master/python/files/requirements_python3.txt\n- NodeJS - https://github.com/Syncano/nodejs-codebox/blob/master/nodejs/files/package.json.j2\n- Ruby - https://github.com/Syncano/ruby-codebox/blob/master/ruby/files/Gemfile\n\nWould you like to add a library to a different language? Let us know by mailing us at [support@syncano.com](mailto:support@syncano.com).\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Running Script\"\n}\n[/block]\nThere are couple of possibilities here:\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Execution method\",\n    \"h-1\": \"Description\",\n    \"0-0\": \"Script.run()\",\n    \"0-1\": \"Scripts can be executed directly with a `run()` method (It might look a bit differently depending on the library of your choice)\",\n    \"1-0\": \"[Script Endpoints](endpoints-scripts)\",\n    \"1-1\": \"With attached Script - with POST or GET to api - first you have to create and configure a Script\",\n    \"2-0\": \"[Schedule Sockets](schedules)\",\n    \"2-1\": \"Syncano will run a Script attached to a Schedule object repeatedly at a schedule that you specify. You have to create a [Schedule](schedules) first\",\n    \"3-0\": \"[Trigger Sockets](triggers)\",\n    \"3-1\": \"Syncano will run a Script attached to a Trigger Socket, when an event described by trigger occurs (i.e. a Data Object is created)\"\n  },\n  \"cols\": 2,\n  \"rows\": 4\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Scripts can only be run with an Account Key! API Key will not work on `/snippets/scripts/` endpoint!\"\n}\n[/block]\nEasiest way to run a Script Snippet is using the [Dashboard](https://dashboard.syncano.io).\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/6zqoJr1QS2WUO5t6bwiA_Run_codebox_01.png\",\n        \"Run_codebox_01.png\",\n        \"1279\",\n        \"654\",\n        \"#27436f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/vL12TUjXT5Gp6i52qFdF_Run_codebox_02.png\",\n        \"Run_codebox_02.png\",\n        \"1279\",\n        \"653\",\n        \"#26416b\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Script Code Example\"\n}\n[/block]\nOk, so once we have our Script created, we can write some code!\n\n### Complex logic in a cloud\n\nWe will run some complex logic in a Script that would be too expensive to compute on mobile or some front-end.\n\nTask: Predict if person likes cats or dogs more? (Not very complex nor expensive but it's an example, ok?!)\n\n![https://www.flickr.com/photos/10233916@N03/3392281751](https://farm4.staticflickr.com/3459/3392281751_e90898ef14_m_d.jpg)\n\nExample input that will be passed in a payload:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\\"first_name\\\": \\\"Ryan\\\", \\\"last_name\\\": \\\"Gosling\\\"}\",\n      \"language\": \"json\",\n      \"name\": \"Input\"\n    }\n  ]\n}\n[/block]\nExample Output:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\\"preferred\\\": \\\"cats\\\"}\\n// OR\\n{\\\"preferred\\\": \\\"dogs\\\"}\",\n      \"language\": \"json\",\n      \"name\": \"Output\"\n    }\n  ]\n}\n[/block]\n Our algorithm will be pretty simple:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import json\\n\\n# Get arguments passed in a payload. You can read about\\n# ARGS in the Script data dictionaries section below\\nfirst_name = ARGS.get(\\\"first_name\\\", None)\\nlast_name = ARGS.get(\\\"last_name\\\", None)\\n\\npreferred = None\\n\\nif first_name and last_name:\\n    if len(first_name) + len(last_name) % 2 == 0:\\n        preferred = 'cats'\\n    else:\\n        preferred = 'dogs'\\n        \\n# now we know, what's the preference!\\n\\n\\n# we only have to dump it as a json and print to std out\\nprint(json.dumps({'preferred': preferred}))\\n\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"// Get arguments passed in a payload. You can read about\\n// ARGS in the Script data dictionaries section below\\nvar first_name = ARGS.first_name;\\nvar last_name = ARGS.last_name;\\nvar preferred;\\n\\nif (first_name && last_name) {\\n  if ((first_name.length + last_name.length) % 2 === 0) {\\n    preferred = \\\"cats\\\";\\n  }\\n  else {\\n    preferred = \\\"dogs\\\";\\n  }\\n}\\n\\n// use console.log to return data\\nconsole.log(\\\"Preferrences: \\\", preferred);\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"require 'json'\\n\\n# Get arguments passed in a payload. You can read about\\n# ARGS in the Script data dictionaries section below\\nfirst_name = ARGS[\\\"first_name\\\"]\\nlast_name = ARGS[\\\"last_name\\\"]\\n\\npreferred = nil\\n\\nif first_name && last_name\\n  if (first_name.length + last_name.length) % 2 == 0\\n    preferred = 'cats'\\n  else\\n    preferred = 'dogs'\\n        \\n# now we know, what's the preference!\\n\\n\\n# we only have to dump it as a json and print to std out\\nputs { preferred: preferred }.to_json\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"// Courtesy of Bryan Smith. \\n// https://github.com/bryanwsmith/syncano-examples-golang/\\n//package main\\n\\nimport (\\n    \\\"fmt\\\"\\n    \\\"log\\\"\\n)\\n\\nfunc main() {\\n\\n//uncomment to test without using Payload option\\n    // ARGS[\\\"first_name\\\"] = \\\"Bryan\\\"\\n    // ARGS[\\\"last_name\\\"] = \\\"Smith\\\"\\n\\n    value, ok := ARGS[\\\"first_name\\\"]\\n    \\n\\n    if !ok { \\n        log.Println(\\\"first_name is required\\\")\\n        return \\n    }\\n\\t\\n\\tfirstName, ok := value.(string)\\n\\n    if !ok { \\n        log.Println(\\\"first_name must be a string\\\")\\n        return \\n    }\\n\\n    value, ok = ARGS[\\\"last_name\\\"]\\n\\t\\n    if !ok { \\n        log.Println(\\\"last_name is required\\\")\\n        return \\n    }\\n    \\n\\tlastName , ok:= value.(string)\\n    \\n    if !ok { \\n        log.Println(\\\"last_name must be a string\\\")\\n        return \\n    }\\n\\n\\tvar preferred = \\\"\\\"\\n\\n\\tif len(firstName) > 0 && len(lastName) > 0 {\\n\\n\\t\\tif (len(firstName)+len(lastName))%2 == 0 {\\n\\t\\t\\tpreferred = \\\"cats\\\"\\n\\t\\t} else {\\n\\t\\t\\tpreferred = \\\"dogs\\\"\\n\\t\\t}\\n\\t}\\n    \\n    result := map[string]string{ \\\"preferred\\\": preferred }\\n    resultBytes, err := json.Marshal(result)\\n    \\n    if err != nil {\\n        log.Println(\\\"failed to serialize result to json\\\")\\n        return\\n    }\\n    \\n    fmt.Println(string(resultBytes))\\n}\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"// Create Enum for more readable code\\n// Each Enum value will have a String raw value assigned\\nenum PreferredAnimal : String {\\n    case None = \\\"None\\\"\\n    case Cat = \\\"Cat\\\"\\n    case Dog = \\\"Dog\\\"\\n}\\n\\n// Before we assign an animal to a name, we set preferred animal to .None - meaning it wasn't chosen yet\\nvar preferredAnimal = PreferredAnimal.None\\n\\n// We check if firstName and lastName were passed in the payload. \\n// If they are not, firstName and lastName are be equal to nil and check fails. \\n// We also make sure passed values aren't just empty strings.\\nif let firstName = ARGS[\\\"first_name\\\"] as! String? where !firstName.isEmpty, \\n   let lastName = ARGS[\\\"last_name\\\"] as! String? where !lastName.isEmpty\\n{\\n    // We 'calculate' based on number of characters in name, \\n    // if preferred animal is a cat or a dog\\n    if (firstName.characters.count + lastName.characters.count) % 2 == 0 {\\n        preferredAnimal = .Cat\\n    } else {\\n        preferredAnimal = .Dog\\n    }\\n}\\n        \\n// now we know, what's the preference!\\n// lets print it as JSON\\nprint(\\\"{\\\\\\\"preferred\\\\\\\":\\\\\\\"\\\\(preferredAnimal.rawValue)\\\\\\\"}\\\")\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIf you are running a Script directly, you can use the same syntax as shown in the section above. \n\n### Running Scripts\nYou can pass data to Script.run() - it will make an asynchronous call \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST \\\\\\n-H \\\"X-API-KEY: ACCOUNT_KEY\\\" \\\\\\n-H \\\"Content-Type: application/json\\\" \\\\\\n-d '{\\\"payload\\\": {\\\"first_name\\\": \\\"Ryan\\\", \\\"last_name\\\": \\\"Gosling\\\"}}'\\\\\\n\\\"https://api.syncano.io/v1.1/instances/instance_name/scripts/snippets/snippet_id/run/\\\"\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import Script \\n\\nsyncano.connect(api_key='ACCOUNT_KEY')\\n\\ntrace = Script.please.run(\\n  instance_name=\\\"INSTANCE_NAME\\\",\\n  id=\\\"SCRIPT_ID\\\",\\n  payload={\\n      'first_name': 'Ryan', \\n      'last_name': 'Gosling'\\n  })\\n\\n\\n# Here, we store the id of the trace in a variable called trace_id.\\n# It will be used if we want to check the results of the trace later.\\ntrace_id = trace.id\\n\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\"); // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar Script = connection.Script;\\n\\nvar query = {\\n  id: 7,\\n\\tinstanceName: \\\"INSTANCE_NAME\\\"\\n}\\n\\nvar payload = {\\n  payload: {\\n    first_name: \\\"John\\\", \\n    last_name: \\\"Snow\\\"\\n  }\\n}\\n\\nScript.please().run(query, payload).then(function(result) {\\n\\tconsole.log(\\\"result\\\", result);\\n});\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"JsonObject params = new JsonObject();\\nparams.addProperty(\\\"first_name\\\", \\\"Ryan\\\");\\nparams.addProperty(\\\"last_name\\\", \\\"Gosling\\\");\\n\\nResponse<Trace> response = syncano.runScript(scriptId, params).send();\\nTrace trace = response.getData();\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"[SCSnippet runSnippetWithId:@(SnippetID) params:@{\\n  @\\\"first_name\\\":@\\\"John\\\",\\n  @\\\"last_name\\\":@\\\"Snow\\\"}\\n completion:^(SCTrace *trace, NSError *error) {\\n   //handle error\\n }];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"SCSnippet.runSnippetWithId(SnippetID, params: [\\n            \\\"first_name\\\":\\\"John\\\",\\n            \\\"last_name\\\":\\\"Snow\\\"]) \\n{ trace, error in\\n  //handle error\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"syncano = SyncanoClient.Instance.Init(\\\"YOUR_API_KEY\\\", \\\"YOUR_INSTANCE_NAME\\\");\\nsyncano.Please().RunScriptEndpointUrl(\\\"ENDPOINT_URL\\\", EndpointCallback);\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nand give you an empty trace, that you can later check for data. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"status\\\":\\\"pending\\\",\\n  \\\"links\\\":\\t\\t{\\n    \\\"self\\\": \\\"/v1.1/instances/syncano/snippets/scripts/446/traces/183/\\\"\\n  },\\n  \\\"executed_at\\\":null,\\n  \\\"result\\\":\\\"\\\",\\n  \\\"duration\\\":null,\\n  \\\"id\\\":183\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n\nRemember to store the \"id\" because you can use it later to check the results of the trace. These results should arrive after a very short time, usually 200ms. You can see below how we access the trace results with the trace id:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl \\\\\\n-H \\\"X-API-KEY: ACCOUNT_KEY\\\" \\\\\\n\\\"https://api.syncano.io/v1.1/instances/syncano/snippets/scripts/script_id/traces/trace_id/\",\n      \"language\": \"curl\"\n    },\n    {\n      \"code\": \"import syncano\\nfrom syncano.models import ScriptTrace\\n \\nsyncano.connect(api_key='ACCOUNT_KEY')\\n \\n  trace = ScriptTrace.please.get(\\n    instance_name='INSTANCE_NAME',\\n    script_id='SCRIPT_ID',\\n    id=trace_id\\n  )\\n\\n  print trace.status\\n  print trace.result\\n# Remember that the \\\"id\\\" variable here is where you should put\\n# the stored variable 'trace_id' from the previous example.\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require(\\\"syncano\\\"); // CommonJS\\nvar connection = Syncano({accountKey: \\\"ACCOUNT_KEY\\\"});\\nvar ScriptTrace = connection.ScriptTrace;\\n\\nvar query = {\\n  scriptId: 7,\\n\\tinstanceName: \\\"INSTANCE_NAME\\\"\\n}\\n\\nScriptTrace.please().list(query).then(function(traces) {\\n\\tconsole.log(\\\"traces\\\", traces);\\n});\",\n      \"language\": \"javascript\"\n    },\n    {\n      \"code\": \"trace.fetch();\\n\\nif (trace.getStatus() == TraceStatus.SUCCESS) {\\n    trace.getOutput();\\n}\",\n      \"language\": \"java\",\n      \"name\": \"Android\"\n    },\n    {\n      \"code\": \"SCTrace *trace = ...//obtain trace from Snippet execution\\n[trace fetchWithCompletion:^(SCTrace *trace, NSError *error) {\\n  //handle error\\n}];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"let trace = ...//obtain trace from Snippet execution\\ntrace.fetchWithCompletion { trace, error in\\n  //handle error\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"Swift\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"private void EndpointCallback(ScriptEndpoint response)\\n{\\n  if(response.IsSuccess)\\n  {\\n    Debug.Log(\\\"success\\\");\\n  }\\n\\n  else\\n  {\\n    Debug.Log(response.syncanoError);\\n  }\\n}\",\n      \"language\": \"csharp\",\n      \"name\": \"Unity\"\n    }\n  ]\n}\n[/block]\nExample response:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"status\\\": \\\"success\\\",\\n    \\\"result\\\": {\\n        \\\"stderr\\\": \\\"\\\",\\n        \\\"stdout\\\": \\\"{\\\\\\\"preferred\\\\\\\": \\\\\\\"dogs\\\\\\\"}\\\"\\n    },\\n    \\\"executed_at\\\": \\\"2015-09-21T14:05:32.800795Z\\\",\\n    \\\"duration\\\": 330,\\n    \\\"id\\\": 18\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Scripts data dictionaries: ARGS, CONFIG, Global CONFIG and META\"\n}\n[/block]\nYou can wonder: \"Hm, these Script thing is pretty cool, but how do I pass data to it?\"\n\nIn every Script Snippet there are three dictionaries with data:\n1. [ARGS](#section-args-dictionary)\n2. [CONFIG](#section-config-dictionary)\n3. [Global CONFIG](#section-global-config-dictionary)\n3. [META](#section-meta-dictionary)\n\n### ARGS dictionary\nARGS is the data passed to the Script. You can think of this data as the arguments to a function. The way we access ARGS is different depending on how you use the Script. You will notice this in our examples below:\n\nIf you'll decide to pass data to a Script when running it directly through the Script `run` method (like in [Running Scripts](#section-running-scripts) section), ARGS dictionary can be accessed this way:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"first_name = ARGS['first_name']\\nlast_name = ARGS['last_name']\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"first_name = ARGS.first_name\\nlast_name = ARGS.last_name\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"first_name = ARGS[\\\"first_name\\\"]\\nlast_name = ARGS[\\\"last_name\\\"]\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"first_name = ARGS[\\\"first_name\\\"]\\nlast_name = ARGS[\\\"last_name\\\"]\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"let firstName = ARGS[\\\"first_name\\\"]\\nlet lastName = ARGS[\\\"last_name\\\"]\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIf you are using the Script from a **Script Endpoint** (you can read more on Script Endpoints [here](doc:endpoints-scripts)), the data in ARGS must be accessed differently in the Script. This is how you can access the data from ARGS if you use a Script Endpoint and you pass the arguments inside of a POST body. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"first_name = ARGS['POST']['first_name']\\nlast_name = ARGS['POST']['last_name']\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"first_name = ARGS.POST.first_name\\nlast_name = ARGS.POST.last_name\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"first_name = ARGS[\\\"POST\\\"][\\\"first_name\\\"]\\nlast_name = ARGS[\\\"POST\\\"][\\\"last_name\\\"]\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"first_name = ARGS[\\\"POST\\\"][\\\"first_name\\\"]\\nlast_name = ARGS[\\\"POST\\\"][\\\"last_name\\\"]\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"let POST = ARGS[\\\"POST\\\"] as? [String: AnyObject]\\nlet firstName = POST?[\\\"first_name\\\"]\\nlet lastName = POST?[\\\"last_name\\\"]\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIf you want to pass arguments in the URL (make a HTTP GET Request), you can access the ARGS data like this\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"first_name = ARGS['GET']['first_name']\\nlast_name = ARGS['GET']['last_name']\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"first_name = ARGS.GET.first_name\\nlast_name = ARGS.GET.last_name\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"first_name = ARGS[\\\"GET\\\"][\\\"first_name\\\"]\\nlast_name = ARGS[\\\"GET\\\"][\\\"last_name\\\"]\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"first_name = ARGS[\\\"GET\\\"][\\\"first_name\\\"]\\nlast_name = ARGS[\\\"GET\\\"][\\\"last_name\\\"]\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"let GET = ARGS[\\\"GET\\\"] as? [String: AnyObject]\\nlet firstName = GET?[\\\"first_name\\\"]\\nlet lastName = GET?[\\\"last_name\\\"]\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\n### CONFIG dictionary\n\nThe configuration specified in the Script config property. Here, you can store passwords, api keys, and other important data. It's not necessary to use it, but it can help you manage your code and make it easier to read. Here is an example CONFIG dictionary:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" {\\n \\t\\\"password\\\": \\\"my_password\\\",\\n  \\\"email\\\": \\\"duke.nukem@gmail.com\\n }\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\nAnd here is an example of a Script that uses CONFIG dictionary to connect to Syncano:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import syncano\\n\\nconnection = syncano.connect(\\n\\temail=CONFIG['email'],\\n\\tpassword=CONFIG[\\\"password\\\"]\\n)\\n\\t\\nprint(list(connection.instances.list()))\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"var Syncano = require('syncano');\\nvar account = new Syncano({accountKey : \\\"ACCOUNT_KEY\\\"});  \\n\\naccount.instance().list(function(err, res) {\\n  if (err) {\\n      console.log(err); return;\\n  }\\n  console.log(res);\\n});\",\n      \"language\": \"javascript\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"require 'syncano'\\n\\nconnection = Syncano.connect(\\n  email: CONFIG['email'],\\n\\tpassword: CONFIG['password'])\\n\\t\\np connection.instances.all\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"//Coming Soon!\",\n      \"language\": \"text\",\n      \"name\": \"Go\"\n    },\n    {\n      \"code\": \"// Syncano librry is not yet available in Swift Snippet, but you can still access CONFIG dictionary\\nlet email = CONFIG[\\\"email\\\"]\\nlet password = CONFIG[\\\"password\\\"]\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIt will list instances that are available in this account:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[<Instance: syncano>, <Instance: brunhilda>, <Instance: tabaluga>]\",\n      \"language\": \"python\"\n    },\n    {\n      \"code\": \"{ prev: null,\\n  objects: \\n   [ { name: 'icy-forest-9448',\\n       links: [Object],\\n       created_at: '2015-09-18T11:46:04.773437Z',\\n       updated_at: '2015-09-18T11:46:04.778263Z',\\n       role: 'full',\\n       owner: [Object],\\n       metadata: [Object],\\n       description: '' },\\n     { name: 'hidden-tree-7627',\\n       links: [Object],\\n       created_at: '2015-09-27T19:27:02.160103Z',\\n       updated_at: '2015-09-27T19:27:02.164393Z',\\n       role: 'full',\\n       owner: [Object],\\n       metadata: [Object],\\n       description: '' },\\n     { name: 'blue-tree-2284',\\n       links: [Object],\\n       created_at: '2015-10-05T07:23:15.885570Z',\\n       updated_at: '2015-10-05T07:23:15.889781Z',\\n       role: 'full',\\n       owner: [Object],\\n       metadata: [Object],\\n       description: '' },\\n     { name: 'sparkling-sunset-9842',\\n       links: [Object],\\n       created_at: '2015-10-05T07:45:30.684964Z',\\n       updated_at: '2015-10-05T07:45:30.691388Z',\\n       role: 'full',\\n       owner: [Object],\\n       metadata: [Object],\\n       description: '' } ],\\n  next: null }\",\n      \"language\": \"json\",\n      \"name\": \"Node.js\"\n    },\n    {\n      \"code\": \"# Coming soon!\",\n      \"language\": \"ruby\"\n    },\n    {\n      \"code\": \"// Coming Soon!\",\n      \"language\": \"go\"\n    },\n    {\n      \"code\": \"// Syncano librry is not yet available in Swift Snippet\",\n      \"language\": \"objectivec\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nYou can set/update CONFIG using our API, but the best way to access it, is through our Dashboard:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/XPqTCa42Qnm6USR2Whob_Config_01.png\",\n        \"Config_01.png\",\n        \"1279\",\n        \"654\",\n        \"#26426d\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n### Global CONFIG dictionary\n\nScript CONFIG dictionary is connected to a single Script. It might be limiting in some cases. For example, if you wanted to reuse one Api Key in multiple Scripts, it would be better to have a single place to store it. And this is exactly what Global CONFIG is for. \n\nGlobal CONFIG is a json object so you can store any valid json data types (`string`, `integer`, `boolean`, `array` etc.) as environment variables. You can access the Global CONFIG right from the comfort of your dashboard: \n\n1. Go to your Instance Details\n2. Choose \"Global Config\" from the bottom of the left menu:\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/DZ8f5bALTYCQE9U5zJFh_global_config_00.png\",\n        \"global_config_00.png\",\n        \"1279\",\n        \"654\",\n        \"#224d83\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n3. Add key value pairs that you want to use in Scripts\n4. Click \"Confirm\" button to save your changes\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/XR7A3lyYQuMKKUz8RwX2_global_config_01.png\",\n        \"global_config_01.png\",\n        \"1279\",\n        \"654\",\n        \"#1677d0\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNow you can access the variables from Global Config the same way as you would from a regular Script Config (you can see how to do this in [CONFIG Dictionary](#section-config-dictionary) section above).\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Important!\",\n  \"body\": \"CONFIG and Global CONFIG dictionaries are merged together when running a Script. If you have two keys with the same name in both config dictionaries, the Global CONFIG key will be **overwritten** by the Snippet Config key. For example:\\nGlobal Config content is: `{\\\"my_variable\\\": \\\"global\\\"}`\\nSnippet Config content is: `{\\\"my_variable\\\": \\\"local\\\"}`\\n\\nWhen you'll access the `my_variable` from snippet, its value will be equal to `local`.\"\n}\n[/block]\n### META Dictionary\nMETA dictionary is the metadata specific to the execution of the Script: information if the Script was run by [Script Endpoint](doc:endpoints-scripts), Schedule or Trigger Socket and other information such as request info for Script Endpoint. This is an example META dictionary:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  'instance': 'red-paper-5274', \\n  'executed_by': 'webhook',\\n  // 'request' key is only present if Script was executed by a Script Endpoint\\n  'request': {'Request details here. Removed from example for brevity'},\\n  'executor': 1\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n### Script Timeouts and Custom Timeout\n\nScripts have a timeout setting built-in. It's default value is currently set to 300 seconds for direct runs. Timeouts for running Scripts via Script Endpoint, Schedule, or Trigger Sockets are different and can be found [here](limits#snippet-scripts). When the Script reaches the timeout limit, its code execution stops and it's status is marked as `timeout` on the Scripts traces list:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/bqwj953TuaP2rbs2xclj_codebox_timeout.png\",\n        \"Snippet_timeout.png\",\n        \"752\",\n        \"60\",\n        \"#e85958\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOn top of that, you can add your own custom timeout setting, to override the default one. \nThe condition here is that the custom timeout cannot exceed the default one -- so it has to be smaller than 300s.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Custom timeout affects only direct Script runs. \\nScript run via Script Endpoint, Schedule or Trigger Sockets will keep their original timeout.\",\n  \"title\": \"Timeout setting for Script Endpoints, Schedules or Triggers Sockets\"\n}\n[/block]\nTo set a custom Script timeout:\n1. Go to Script Config tab\n2. Add a \"timeout\" Key\n3. Add a Value in 1 - 299 second range \n4. Select \"Integer\" as Value Type\n5. Click \"+\" button to add this field to Script Config\n6. Click \"Save\" button to save the Script Config\n \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/YFh6C4XzROiLPSBtXHe2_Timeout_01.png\",\n        \"Timeout_01.png\",\n        \"1283\",\n        \"604\",\n        \"#c5185f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Handling files in Scripts\"\n}\n[/block]\nScript Snippets allow for operations on files too. Each script is a separate environment and during script run you'll have access to the filesystem operations. The data on filesystem is temporary and is accessible only during the script execution. If you'd like to use the data in the future the best approach would be to save it as Data Object once you are done processing it. We will go through a common use case of processing a pdf file to show how it works. In the example below a script will:\n1. Get a file from a url\n2. Write the file to a temporary directory\n3. Zip the file\n4. Save the file as a Data Object\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Currently there's no file size limit for storage during Script execution.\"\n}\n[/block]\nPrerequisites:\nFor this example to work, you'll need:\n1. An [Account Key](doc:authentication) \n2. A [Data Class](doc:classes) called `zip` with the following schema:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[\\n  {\\n    \\\"name\\\": \\\"file\\\",\\n    \\\"type\\\": \\\"file\\\"\\n  },\\n  {\\n    \\\"name\\\": \\\"file_url\\\",\\n    \\\"type\\\": \\\"string\\\"\\n  }\\n]\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n3. You'll also need to pass the following payload when executing the Script:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"file_url\\\": \\\"a url to pdf file\\\"\\n}\",\n      \"language\": \"json\"\n    }\n  ]\n}\n[/block]\n### The file handling example\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"from syncano.models import Object\\nimport syncano\\nimport requests\\nimport zipfile\\nimport tempfile\\nimport os\\n\\nsyncano.connect(api_key=\\\"ACCOUNT_KEY\\\")\\n\\nfile_url = ARGS.get('file_url', None)\\nif file_url is None:\\n    raise ValueError(\\\"You didn't pass file_url to your CodeBox Execution\\\")\\n\\n# get pdf file from url\\nfile = requests.get(file_url)\\n\\n# set up temporary directory and save the pdf file in it\\ntemp_directory = tempfile.mkdtemp()\\npdf_file_name = temp_directory + \\\"/pdf_file.pdf\\\"\\nf = open(pdf_file_name, \\\"wb\\\")\\nf.write(file.content)\\nf.close()\\n\\n# zip the file we placed in the temp directory\\nzipped_path = temp_directory + \\\"/pdf_zipped.zip\\\"\\nwith zipfile.ZipFile(zipped_path, \\\"w\\\") as zf:\\n    zf.write(pdf_file_name, os.path.basename(pdf_file_name))\\n\\n# Save zipped file to Syncano\\nfile = open(zipped_path, \\\"r\\\")\\nObject.please.create(instance_name=META[\\\"instance\\\"],\\n                     class_name=\\\"zip\\\",\\n                     file=file,\\n                     file_url=file_url)\\nfile.close()\",\n      \"language\": \"python\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Summary\"\n}\n[/block]\nNow you know how to create and run Scripts. Next step is learning more about running them by using [Script Endpoints](doc:endpoints-scripts), [Schedule](doc:schedules) and [Trigger](doc:triggers) Sockets.\n\nAlternatively you can read about another type of code that can be stored on Syncano which is called Template Snippets. They allow for creation of, for instance, html views out of any of the Syncano endpoints. You can read more about templates [here](http://docs.syncano.io/v1.1/docs/snippets-templates).","excerpt":"How do you run Snippet Scripts on Syncano? What can they do?","slug":"snippets-scripts","type":"basic","title":"Snippets - Scripts"}

Snippets - Scripts

How do you run Snippet Scripts on Syncano? What can they do?

## Chapter Contents: 1. [Overview](#overview) 2. [Adding a new Script](#adding-a-new-script) 3. [Runtimes and libraries](#runtimes-and-libraries) 4. [Running a Script](#running-script) 5. [Script Example](#script-code-example) 6. [Scripts data dictionaries: ARGS, CONFIG, Global CONFIG and META](#scripts-data-dictionaries-args-config-global-confi) 7. [Custom Script Timeouts](#section-script-timeouts-and-custom-timeout) 8. [Handling files in Scripts](#handling-files-in-scripts) 9. [Summary](#summary) [block:api-header] { "type": "basic", "title": "Overview" } [/block] A [Script](glossary#section-snippet-script) is an object that contains code that can be run on Syncano's servers. ### What can be accomplished with a Script A Script is a very powerful tool. Just like with code, you can do a lot with it. Additionally, Syncano gives you many ways to run Scripts. This is where you can get creative. With a Script you can: - compute tasks that are too expensive to compute on mobile/frontend side. - create your own logic in the cloud that can be accessed by an API built on Script Endpoints (complex filtering, composing multiple objects) - handle events on Syncano with Trigger Sockets - trigger jobs in the cloud with the API - run scheduled jobs - cloud cron - build your own integrations between services with Scripts powered Script Endpoints - create public Script Endpoints available for people that know the link [block:callout] { "type": "info", "title": "Note on pricing", "body": "Scripts pricing is based on total execution time. So, in terms of billing, 30 Script runs that took 1 second each are equal to one Script run that took 30 seconds. Builder plan allows for 20.000 (twenty thousand) Script seconds per month." } [/block] ### Script Properties So what exactly is this Script? This is how a Script object can look like: [block:code] { "codes": [ { "code": "{\n \"config\": {}, \n \"id\": 1, \n \"runtime_name\": \"python\", \n \"label\": \"here\", \n \"description\": \"there\", \n \"source\": \"print('ello')\", \n \"created_at\": \"2015-01-28T14:02:38.408864Z\", \n \"updated_at\": \"2015-01-28T14:02:38.408920Z\", \n \"links\": {\n \"traces\": \"/v1.1/instances/syncano/snippets/scripts/1/traces/\", \n \"self\": \"/v1.1/instances/syncano/snippets/scripts/1/\", \n \"run\": \"/v1.1/instances/syncano/snippets/scripts/1/run/\", \n \"runtimes\": \"/v1.1/instances/syncano/snippets/scripts/runtimes/\"\n }\n}", "language": "json" } ] } [/block] And here's an overview of the unique properties that Script has: [block:parameters] { "data": { "h-0": "Property", "h-1": "Description", "0-0": "`runtime_name`", "0-1": "The `runtime environment` that the Script will run in (i.e. Ruby, Python, NodeJS, Golang, Swift and PHP). Every language is supported by a different runtime environment. The runtime environment also supports several libraries for each language. For example: The Python runtime has a `requests` library.", "1-0": "`source`", "1-1": "A piece of code that will run when the Script is executed.", "2-0": "`label`", "2-1": "Label of the Script", "3-0": "`description`", "3-1": "Script description", "4-1": "A very useful field that can be used to store your confidential data such as APIKEYS or any other configurable variables.", "4-0": "`config`" }, "cols": 2, "rows": 5 } [/block] [block:callout] { "type": "info", "title": "For advanced users:", "body": "Runtimes are described by Dockerfiles, you can find all of them on our Github account:\n- https://github.com/Syncano/python-codebox\n- https://github.com/Syncano/golang-codebox\n- https://github.com/Syncano/nodejs-codebox\n- https://github.com/Syncano/ruby-codebox\n- https://github.com/syncano/swift-codebox\n- https://github.com/syncano/php-codebox" } [/block] [block:api-header] { "type": "basic", "title": "Adding a new Script" } [/block] The easiest way to add a new Script, is with help of the [Dashboard](https://dashboard.syncano.io). [block:image] { "images": [ { "image": [ "https://files.readme.io/outHfAyPQmC37wwuQddD_Add_codebox_01.png", "Add_codebox_01.png", "1279", "654", "#234473", "" ] } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/e3fMoPDSRIqeLNqMnlIF_Add_codebox_02.png", "Add_codebox_02.png", "1279", "655", "#6c84a4", "" ] } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/ihQC7RZtSlWF9DIoNM7g_Add_codebox_03.png", "Add_codebox_03.png", "1279", "653", "#25426f", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Runtimes and libraries" } [/block] It is possible to write your code in one of few selected runtimes. You can always find most up-to-date list with supported languages using our API. To do so, make a GET request on an `/instances/:instance_name/scripts/snippets/runtimes/` endpoint, e.g.: [block:code] { "codes": [ { "code": "curl -X GET \\\n-H \"X-API-KEY: <ACCOUNT_KEY>\" \\\n\"https://api.syncano.io/v1.1/instances/<instance_name>/scripts/snippets/runtimes/\"", "language": "curl" } ] } [/block] As of October 2016, we support following programming languages/runtimes: - NodeJS - Python - Swift - Golang - PHP - Ruby For some of the languages, we support adding libraries/packages, from popular repositories/package managers. Currently it is not possible to define packages available in a Script using our Dashboard. Instead, to request a new library: - Write to us at [support@syncano.com](mailto:support@syncano.com). Let us know which library you'd like to have added for which language; - or make a pull request to our repository (and change a file with list of available libraries) You can find listing of libraries available in a Script on our GitHub: - Python 2.7 - https://github.com/Syncano/python-codebox/blob/master/python/files/requirements.txt - Python 3 - https://github.com/Syncano/python-codebox/blob/master/python/files/requirements_python3.txt - NodeJS - https://github.com/Syncano/nodejs-codebox/blob/master/nodejs/files/package.json.j2 - Ruby - https://github.com/Syncano/ruby-codebox/blob/master/ruby/files/Gemfile Would you like to add a library to a different language? Let us know by mailing us at [support@syncano.com](mailto:support@syncano.com). [block:api-header] { "type": "basic", "title": "Running Script" } [/block] There are couple of possibilities here: [block:parameters] { "data": { "h-0": "Execution method", "h-1": "Description", "0-0": "Script.run()", "0-1": "Scripts can be executed directly with a `run()` method (It might look a bit differently depending on the library of your choice)", "1-0": "[Script Endpoints](endpoints-scripts)", "1-1": "With attached Script - with POST or GET to api - first you have to create and configure a Script", "2-0": "[Schedule Sockets](schedules)", "2-1": "Syncano will run a Script attached to a Schedule object repeatedly at a schedule that you specify. You have to create a [Schedule](schedules) first", "3-0": "[Trigger Sockets](triggers)", "3-1": "Syncano will run a Script attached to a Trigger Socket, when an event described by trigger occurs (i.e. a Data Object is created)" }, "cols": 2, "rows": 4 } [/block] [block:callout] { "type": "warning", "body": "Scripts can only be run with an Account Key! API Key will not work on `/snippets/scripts/` endpoint!" } [/block] Easiest way to run a Script Snippet is using the [Dashboard](https://dashboard.syncano.io). [block:image] { "images": [ { "image": [ "https://files.readme.io/6zqoJr1QS2WUO5t6bwiA_Run_codebox_01.png", "Run_codebox_01.png", "1279", "654", "#27436f", "" ] } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/vL12TUjXT5Gp6i52qFdF_Run_codebox_02.png", "Run_codebox_02.png", "1279", "653", "#26416b", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Script Code Example" } [/block] Ok, so once we have our Script created, we can write some code! ### Complex logic in a cloud We will run some complex logic in a Script that would be too expensive to compute on mobile or some front-end. Task: Predict if person likes cats or dogs more? (Not very complex nor expensive but it's an example, ok?!) ![https://www.flickr.com/photos/10233916@N03/3392281751](https://farm4.staticflickr.com/3459/3392281751_e90898ef14_m_d.jpg) Example input that will be passed in a payload: [block:code] { "codes": [ { "code": "{\"first_name\": \"Ryan\", \"last_name\": \"Gosling\"}", "language": "json", "name": "Input" } ] } [/block] Example Output: [block:code] { "codes": [ { "code": "{\"preferred\": \"cats\"}\n// OR\n{\"preferred\": \"dogs\"}", "language": "json", "name": "Output" } ] } [/block] Our algorithm will be pretty simple: [block:code] { "codes": [ { "code": "import json\n\n# Get arguments passed in a payload. You can read about\n# ARGS in the Script data dictionaries section below\nfirst_name = ARGS.get(\"first_name\", None)\nlast_name = ARGS.get(\"last_name\", None)\n\npreferred = None\n\nif first_name and last_name:\n if len(first_name) + len(last_name) % 2 == 0:\n preferred = 'cats'\n else:\n preferred = 'dogs'\n \n# now we know, what's the preference!\n\n\n# we only have to dump it as a json and print to std out\nprint(json.dumps({'preferred': preferred}))\n", "language": "python" }, { "code": "// Get arguments passed in a payload. You can read about\n// ARGS in the Script data dictionaries section below\nvar first_name = ARGS.first_name;\nvar last_name = ARGS.last_name;\nvar preferred;\n\nif (first_name && last_name) {\n if ((first_name.length + last_name.length) % 2 === 0) {\n preferred = \"cats\";\n }\n else {\n preferred = \"dogs\";\n }\n}\n\n// use console.log to return data\nconsole.log(\"Preferrences: \", preferred);", "language": "javascript", "name": "Node.js" }, { "code": "require 'json'\n\n# Get arguments passed in a payload. You can read about\n# ARGS in the Script data dictionaries section below\nfirst_name = ARGS[\"first_name\"]\nlast_name = ARGS[\"last_name\"]\n\npreferred = nil\n\nif first_name && last_name\n if (first_name.length + last_name.length) % 2 == 0\n preferred = 'cats'\n else\n preferred = 'dogs'\n \n# now we know, what's the preference!\n\n\n# we only have to dump it as a json and print to std out\nputs { preferred: preferred }.to_json", "language": "ruby" }, { "code": "// Courtesy of Bryan Smith. \n// https://github.com/bryanwsmith/syncano-examples-golang/\n//package main\n\nimport (\n \"fmt\"\n \"log\"\n)\n\nfunc main() {\n\n//uncomment to test without using Payload option\n // ARGS[\"first_name\"] = \"Bryan\"\n // ARGS[\"last_name\"] = \"Smith\"\n\n value, ok := ARGS[\"first_name\"]\n \n\n if !ok { \n log.Println(\"first_name is required\")\n return \n }\n\t\n\tfirstName, ok := value.(string)\n\n if !ok { \n log.Println(\"first_name must be a string\")\n return \n }\n\n value, ok = ARGS[\"last_name\"]\n\t\n if !ok { \n log.Println(\"last_name is required\")\n return \n }\n \n\tlastName , ok:= value.(string)\n \n if !ok { \n log.Println(\"last_name must be a string\")\n return \n }\n\n\tvar preferred = \"\"\n\n\tif len(firstName) > 0 && len(lastName) > 0 {\n\n\t\tif (len(firstName)+len(lastName))%2 == 0 {\n\t\t\tpreferred = \"cats\"\n\t\t} else {\n\t\t\tpreferred = \"dogs\"\n\t\t}\n\t}\n \n result := map[string]string{ \"preferred\": preferred }\n resultBytes, err := json.Marshal(result)\n \n if err != nil {\n log.Println(\"failed to serialize result to json\")\n return\n }\n \n fmt.Println(string(resultBytes))\n}", "language": "go" }, { "code": "// Create Enum for more readable code\n// Each Enum value will have a String raw value assigned\nenum PreferredAnimal : String {\n case None = \"None\"\n case Cat = \"Cat\"\n case Dog = \"Dog\"\n}\n\n// Before we assign an animal to a name, we set preferred animal to .None - meaning it wasn't chosen yet\nvar preferredAnimal = PreferredAnimal.None\n\n// We check if firstName and lastName were passed in the payload. \n// If they are not, firstName and lastName are be equal to nil and check fails. \n// We also make sure passed values aren't just empty strings.\nif let firstName = ARGS[\"first_name\"] as! String? where !firstName.isEmpty, \n let lastName = ARGS[\"last_name\"] as! String? where !lastName.isEmpty\n{\n // We 'calculate' based on number of characters in name, \n // if preferred animal is a cat or a dog\n if (firstName.characters.count + lastName.characters.count) % 2 == 0 {\n preferredAnimal = .Cat\n } else {\n preferredAnimal = .Dog\n }\n}\n \n// now we know, what's the preference!\n// lets print it as JSON\nprint(\"{\\\"preferred\\\":\\\"\\(preferredAnimal.rawValue)\\\"}\")", "language": "objectivec", "name": "Swift" } ] } [/block] If you are running a Script directly, you can use the same syntax as shown in the section above. ### Running Scripts You can pass data to Script.run() - it will make an asynchronous call [block:code] { "codes": [ { "code": "curl -X POST \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n-H \"Content-Type: application/json\" \\\n-d '{\"payload\": {\"first_name\": \"Ryan\", \"last_name\": \"Gosling\"}}'\\\n\"https://api.syncano.io/v1.1/instances/instance_name/scripts/snippets/snippet_id/run/\"", "language": "curl" }, { "code": "import syncano\nfrom syncano.models import Script \n\nsyncano.connect(api_key='ACCOUNT_KEY')\n\ntrace = Script.please.run(\n instance_name=\"INSTANCE_NAME\",\n id=\"SCRIPT_ID\",\n payload={\n 'first_name': 'Ryan', \n 'last_name': 'Gosling'\n })\n\n\n# Here, we store the id of the trace in a variable called trace_id.\n# It will be used if we want to check the results of the trace later.\ntrace_id = trace.id\n", "language": "python" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar Script = connection.Script;\n\nvar query = {\n id: 7,\n\tinstanceName: \"INSTANCE_NAME\"\n}\n\nvar payload = {\n payload: {\n first_name: \"John\", \n last_name: \"Snow\"\n }\n}\n\nScript.please().run(query, payload).then(function(result) {\n\tconsole.log(\"result\", result);\n});", "language": "javascript" }, { "code": "JsonObject params = new JsonObject();\nparams.addProperty(\"first_name\", \"Ryan\");\nparams.addProperty(\"last_name\", \"Gosling\");\n\nResponse<Trace> response = syncano.runScript(scriptId, params).send();\nTrace trace = response.getData();", "language": "java", "name": "Android" }, { "code": "[SCSnippet runSnippetWithId:@(SnippetID) params:@{\n @\"first_name\":@\"John\",\n @\"last_name\":@\"Snow\"}\n completion:^(SCTrace *trace, NSError *error) {\n //handle error\n }];", "language": "objectivec" }, { "code": "SCSnippet.runSnippetWithId(SnippetID, params: [\n \"first_name\":\"John\",\n \"last_name\":\"Snow\"]) \n{ trace, error in\n //handle error\n}", "language": "javascript", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "syncano = SyncanoClient.Instance.Init(\"YOUR_API_KEY\", \"YOUR_INSTANCE_NAME\");\nsyncano.Please().RunScriptEndpointUrl(\"ENDPOINT_URL\", EndpointCallback);", "language": "csharp", "name": "Unity" } ] } [/block] and give you an empty trace, that you can later check for data. [block:code] { "codes": [ { "code": "{\n \"status\":\"pending\",\n \"links\":\t\t{\n \"self\": \"/v1.1/instances/syncano/snippets/scripts/446/traces/183/\"\n },\n \"executed_at\":null,\n \"result\":\"\",\n \"duration\":null,\n \"id\":183\n}", "language": "json" } ] } [/block] Remember to store the "id" because you can use it later to check the results of the trace. These results should arrive after a very short time, usually 200ms. You can see below how we access the trace results with the trace id: [block:code] { "codes": [ { "code": "curl \\\n-H \"X-API-KEY: ACCOUNT_KEY\" \\\n\"https://api.syncano.io/v1.1/instances/syncano/snippets/scripts/script_id/traces/trace_id/", "language": "curl" }, { "code": "import syncano\nfrom syncano.models import ScriptTrace\n \nsyncano.connect(api_key='ACCOUNT_KEY')\n \n trace = ScriptTrace.please.get(\n instance_name='INSTANCE_NAME',\n script_id='SCRIPT_ID',\n id=trace_id\n )\n\n print trace.status\n print trace.result\n# Remember that the \"id\" variable here is where you should put\n# the stored variable 'trace_id' from the previous example.", "language": "python" }, { "code": "var Syncano = require(\"syncano\"); // CommonJS\nvar connection = Syncano({accountKey: \"ACCOUNT_KEY\"});\nvar ScriptTrace = connection.ScriptTrace;\n\nvar query = {\n scriptId: 7,\n\tinstanceName: \"INSTANCE_NAME\"\n}\n\nScriptTrace.please().list(query).then(function(traces) {\n\tconsole.log(\"traces\", traces);\n});", "language": "javascript" }, { "code": "trace.fetch();\n\nif (trace.getStatus() == TraceStatus.SUCCESS) {\n trace.getOutput();\n}", "language": "java", "name": "Android" }, { "code": "SCTrace *trace = ...//obtain trace from Snippet execution\n[trace fetchWithCompletion:^(SCTrace *trace, NSError *error) {\n //handle error\n}];", "language": "objectivec" }, { "code": "let trace = ...//obtain trace from Snippet execution\ntrace.fetchWithCompletion { trace, error in\n //handle error\n}", "language": "javascript", "name": "Swift" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "private void EndpointCallback(ScriptEndpoint response)\n{\n if(response.IsSuccess)\n {\n Debug.Log(\"success\");\n }\n\n else\n {\n Debug.Log(response.syncanoError);\n }\n}", "language": "csharp", "name": "Unity" } ] } [/block] Example response: [block:code] { "codes": [ { "code": "{\n \"status\": \"success\",\n \"result\": {\n \"stderr\": \"\",\n \"stdout\": \"{\\\"preferred\\\": \\\"dogs\\\"}\"\n },\n \"executed_at\": \"2015-09-21T14:05:32.800795Z\",\n \"duration\": 330,\n \"id\": 18\n}", "language": "json" } ] } [/block] [block:api-header] { "type": "basic", "title": "Scripts data dictionaries: ARGS, CONFIG, Global CONFIG and META" } [/block] You can wonder: "Hm, these Script thing is pretty cool, but how do I pass data to it?" In every Script Snippet there are three dictionaries with data: 1. [ARGS](#section-args-dictionary) 2. [CONFIG](#section-config-dictionary) 3. [Global CONFIG](#section-global-config-dictionary) 3. [META](#section-meta-dictionary) ### ARGS dictionary ARGS is the data passed to the Script. You can think of this data as the arguments to a function. The way we access ARGS is different depending on how you use the Script. You will notice this in our examples below: If you'll decide to pass data to a Script when running it directly through the Script `run` method (like in [Running Scripts](#section-running-scripts) section), ARGS dictionary can be accessed this way: [block:code] { "codes": [ { "code": "first_name = ARGS['first_name']\nlast_name = ARGS['last_name']", "language": "python" }, { "code": "first_name = ARGS.first_name\nlast_name = ARGS.last_name", "language": "javascript", "name": "Node.js" }, { "code": "first_name = ARGS[\"first_name\"]\nlast_name = ARGS[\"last_name\"]", "language": "ruby" }, { "code": "first_name = ARGS[\"first_name\"]\nlast_name = ARGS[\"last_name\"]", "language": "go" }, { "code": "let firstName = ARGS[\"first_name\"]\nlet lastName = ARGS[\"last_name\"]", "language": "objectivec", "name": "Swift" } ] } [/block] If you are using the Script from a **Script Endpoint** (you can read more on Script Endpoints [here](doc:endpoints-scripts)), the data in ARGS must be accessed differently in the Script. This is how you can access the data from ARGS if you use a Script Endpoint and you pass the arguments inside of a POST body. [block:code] { "codes": [ { "code": "first_name = ARGS['POST']['first_name']\nlast_name = ARGS['POST']['last_name']", "language": "python" }, { "code": "first_name = ARGS.POST.first_name\nlast_name = ARGS.POST.last_name", "language": "javascript", "name": "Node.js" }, { "code": "first_name = ARGS[\"POST\"][\"first_name\"]\nlast_name = ARGS[\"POST\"][\"last_name\"]", "language": "ruby" }, { "code": "first_name = ARGS[\"POST\"][\"first_name\"]\nlast_name = ARGS[\"POST\"][\"last_name\"]", "language": "go" }, { "code": "let POST = ARGS[\"POST\"] as? [String: AnyObject]\nlet firstName = POST?[\"first_name\"]\nlet lastName = POST?[\"last_name\"]", "language": "objectivec", "name": "Swift" } ] } [/block] If you want to pass arguments in the URL (make a HTTP GET Request), you can access the ARGS data like this [block:code] { "codes": [ { "code": "first_name = ARGS['GET']['first_name']\nlast_name = ARGS['GET']['last_name']", "language": "python" }, { "code": "first_name = ARGS.GET.first_name\nlast_name = ARGS.GET.last_name", "language": "javascript", "name": "Node.js" }, { "code": "first_name = ARGS[\"GET\"][\"first_name\"]\nlast_name = ARGS[\"GET\"][\"last_name\"]", "language": "ruby" }, { "code": "first_name = ARGS[\"GET\"][\"first_name\"]\nlast_name = ARGS[\"GET\"][\"last_name\"]", "language": "go" }, { "code": "let GET = ARGS[\"GET\"] as? [String: AnyObject]\nlet firstName = GET?[\"first_name\"]\nlet lastName = GET?[\"last_name\"]", "language": "objectivec", "name": "Swift" } ] } [/block] ### CONFIG dictionary The configuration specified in the Script config property. Here, you can store passwords, api keys, and other important data. It's not necessary to use it, but it can help you manage your code and make it easier to read. Here is an example CONFIG dictionary: [block:code] { "codes": [ { "code": " {\n \t\"password\": \"my_password\",\n \"email\": \"duke.nukem@gmail.com\n }", "language": "json" } ] } [/block] And here is an example of a Script that uses CONFIG dictionary to connect to Syncano: [block:code] { "codes": [ { "code": "import syncano\n\nconnection = syncano.connect(\n\temail=CONFIG['email'],\n\tpassword=CONFIG[\"password\"]\n)\n\t\nprint(list(connection.instances.list()))", "language": "python" }, { "code": "var Syncano = require('syncano');\nvar account = new Syncano({accountKey : \"ACCOUNT_KEY\"}); \n\naccount.instance().list(function(err, res) {\n if (err) {\n console.log(err); return;\n }\n console.log(res);\n});", "language": "javascript", "name": "Node.js" }, { "code": "require 'syncano'\n\nconnection = Syncano.connect(\n email: CONFIG['email'],\n\tpassword: CONFIG['password'])\n\t\np connection.instances.all", "language": "ruby" }, { "code": "//Coming Soon!", "language": "text", "name": "Go" }, { "code": "// Syncano librry is not yet available in Swift Snippet, but you can still access CONFIG dictionary\nlet email = CONFIG[\"email\"]\nlet password = CONFIG[\"password\"]", "language": "objectivec", "name": "Swift" } ] } [/block] It will list instances that are available in this account: [block:code] { "codes": [ { "code": "[<Instance: syncano>, <Instance: brunhilda>, <Instance: tabaluga>]", "language": "python" }, { "code": "{ prev: null,\n objects: \n [ { name: 'icy-forest-9448',\n links: [Object],\n created_at: '2015-09-18T11:46:04.773437Z',\n updated_at: '2015-09-18T11:46:04.778263Z',\n role: 'full',\n owner: [Object],\n metadata: [Object],\n description: '' },\n { name: 'hidden-tree-7627',\n links: [Object],\n created_at: '2015-09-27T19:27:02.160103Z',\n updated_at: '2015-09-27T19:27:02.164393Z',\n role: 'full',\n owner: [Object],\n metadata: [Object],\n description: '' },\n { name: 'blue-tree-2284',\n links: [Object],\n created_at: '2015-10-05T07:23:15.885570Z',\n updated_at: '2015-10-05T07:23:15.889781Z',\n role: 'full',\n owner: [Object],\n metadata: [Object],\n description: '' },\n { name: 'sparkling-sunset-9842',\n links: [Object],\n created_at: '2015-10-05T07:45:30.684964Z',\n updated_at: '2015-10-05T07:45:30.691388Z',\n role: 'full',\n owner: [Object],\n metadata: [Object],\n description: '' } ],\n next: null }", "language": "json", "name": "Node.js" }, { "code": "# Coming soon!", "language": "ruby" }, { "code": "// Coming Soon!", "language": "go" }, { "code": "// Syncano librry is not yet available in Swift Snippet", "language": "objectivec", "name": "Swift" } ] } [/block] You can set/update CONFIG using our API, but the best way to access it, is through our Dashboard: [block:image] { "images": [ { "image": [ "https://files.readme.io/XPqTCa42Qnm6USR2Whob_Config_01.png", "Config_01.png", "1279", "654", "#26426d", "" ] } ] } [/block] ### Global CONFIG dictionary Script CONFIG dictionary is connected to a single Script. It might be limiting in some cases. For example, if you wanted to reuse one Api Key in multiple Scripts, it would be better to have a single place to store it. And this is exactly what Global CONFIG is for. Global CONFIG is a json object so you can store any valid json data types (`string`, `integer`, `boolean`, `array` etc.) as environment variables. You can access the Global CONFIG right from the comfort of your dashboard: 1. Go to your Instance Details 2. Choose "Global Config" from the bottom of the left menu: [block:image] { "images": [ { "image": [ "https://files.readme.io/DZ8f5bALTYCQE9U5zJFh_global_config_00.png", "global_config_00.png", "1279", "654", "#224d83", "" ] } ] } [/block] 3. Add key value pairs that you want to use in Scripts 4. Click "Confirm" button to save your changes [block:image] { "images": [ { "image": [ "https://files.readme.io/XR7A3lyYQuMKKUz8RwX2_global_config_01.png", "global_config_01.png", "1279", "654", "#1677d0", "" ] } ] } [/block] Now you can access the variables from Global Config the same way as you would from a regular Script Config (you can see how to do this in [CONFIG Dictionary](#section-config-dictionary) section above). [block:callout] { "type": "warning", "title": "Important!", "body": "CONFIG and Global CONFIG dictionaries are merged together when running a Script. If you have two keys with the same name in both config dictionaries, the Global CONFIG key will be **overwritten** by the Snippet Config key. For example:\nGlobal Config content is: `{\"my_variable\": \"global\"}`\nSnippet Config content is: `{\"my_variable\": \"local\"}`\n\nWhen you'll access the `my_variable` from snippet, its value will be equal to `local`." } [/block] ### META Dictionary META dictionary is the metadata specific to the execution of the Script: information if the Script was run by [Script Endpoint](doc:endpoints-scripts), Schedule or Trigger Socket and other information such as request info for Script Endpoint. This is an example META dictionary: [block:code] { "codes": [ { "code": "{\n 'instance': 'red-paper-5274', \n 'executed_by': 'webhook',\n // 'request' key is only present if Script was executed by a Script Endpoint\n 'request': {'Request details here. Removed from example for brevity'},\n 'executor': 1\n}", "language": "json" } ] } [/block] ### Script Timeouts and Custom Timeout Scripts have a timeout setting built-in. It's default value is currently set to 300 seconds for direct runs. Timeouts for running Scripts via Script Endpoint, Schedule, or Trigger Sockets are different and can be found [here](limits#snippet-scripts). When the Script reaches the timeout limit, its code execution stops and it's status is marked as `timeout` on the Scripts traces list: [block:image] { "images": [ { "image": [ "https://files.readme.io/bqwj953TuaP2rbs2xclj_codebox_timeout.png", "Snippet_timeout.png", "752", "60", "#e85958", "" ] } ] } [/block] On top of that, you can add your own custom timeout setting, to override the default one. The condition here is that the custom timeout cannot exceed the default one -- so it has to be smaller than 300s. [block:callout] { "type": "warning", "body": "Custom timeout affects only direct Script runs. \nScript run via Script Endpoint, Schedule or Trigger Sockets will keep their original timeout.", "title": "Timeout setting for Script Endpoints, Schedules or Triggers Sockets" } [/block] To set a custom Script timeout: 1. Go to Script Config tab 2. Add a "timeout" Key 3. Add a Value in 1 - 299 second range 4. Select "Integer" as Value Type 5. Click "+" button to add this field to Script Config 6. Click "Save" button to save the Script Config [block:image] { "images": [ { "image": [ "https://files.readme.io/YFh6C4XzROiLPSBtXHe2_Timeout_01.png", "Timeout_01.png", "1283", "604", "#c5185f", "" ] } ] } [/block] [block:api-header] { "type": "basic", "title": "Handling files in Scripts" } [/block] Script Snippets allow for operations on files too. Each script is a separate environment and during script run you'll have access to the filesystem operations. The data on filesystem is temporary and is accessible only during the script execution. If you'd like to use the data in the future the best approach would be to save it as Data Object once you are done processing it. We will go through a common use case of processing a pdf file to show how it works. In the example below a script will: 1. Get a file from a url 2. Write the file to a temporary directory 3. Zip the file 4. Save the file as a Data Object [block:callout] { "type": "info", "body": "Currently there's no file size limit for storage during Script execution." } [/block] Prerequisites: For this example to work, you'll need: 1. An [Account Key](doc:authentication) 2. A [Data Class](doc:classes) called `zip` with the following schema: [block:code] { "codes": [ { "code": "[\n {\n \"name\": \"file\",\n \"type\": \"file\"\n },\n {\n \"name\": \"file_url\",\n \"type\": \"string\"\n }\n]", "language": "json" } ] } [/block] 3. You'll also need to pass the following payload when executing the Script: [block:code] { "codes": [ { "code": "{\n \"file_url\": \"a url to pdf file\"\n}", "language": "json" } ] } [/block] ### The file handling example [block:code] { "codes": [ { "code": "from syncano.models import Object\nimport syncano\nimport requests\nimport zipfile\nimport tempfile\nimport os\n\nsyncano.connect(api_key=\"ACCOUNT_KEY\")\n\nfile_url = ARGS.get('file_url', None)\nif file_url is None:\n raise ValueError(\"You didn't pass file_url to your CodeBox Execution\")\n\n# get pdf file from url\nfile = requests.get(file_url)\n\n# set up temporary directory and save the pdf file in it\ntemp_directory = tempfile.mkdtemp()\npdf_file_name = temp_directory + \"/pdf_file.pdf\"\nf = open(pdf_file_name, \"wb\")\nf.write(file.content)\nf.close()\n\n# zip the file we placed in the temp directory\nzipped_path = temp_directory + \"/pdf_zipped.zip\"\nwith zipfile.ZipFile(zipped_path, \"w\") as zf:\n zf.write(pdf_file_name, os.path.basename(pdf_file_name))\n\n# Save zipped file to Syncano\nfile = open(zipped_path, \"r\")\nObject.please.create(instance_name=META[\"instance\"],\n class_name=\"zip\",\n file=file,\n file_url=file_url)\nfile.close()", "language": "python" } ] } [/block] [block:api-header] { "type": "basic", "title": "Summary" } [/block] Now you know how to create and run Scripts. Next step is learning more about running them by using [Script Endpoints](doc:endpoints-scripts), [Schedule](doc:schedules) and [Trigger](doc:triggers) Sockets. Alternatively you can read about another type of code that can be stored on Syncano which is called Template Snippets. They allow for creation of, for instance, html views out of any of the Syncano endpoints. You can read more about templates [here](http://docs.syncano.io/v1.1/docs/snippets-templates).