{"_id":"588f722cbcace50f0052ba10","version":{"_id":"588f722bbcace50f0052b9e1","project":"565f5fa26bafd40d0030a064","__v":1,"createdAt":"2017-01-30T17:04:43.410Z","releaseDate":"2017-01-30T17:04:43.410Z","categories":["588f722bbcace50f0052b9e2","588f722bbcace50f0052b9e3","588f722bbcace50f0052b9e4","588f722bbcace50f0052b9e5","588f722bbcace50f0052b9e6","588f722bbcace50f0052b9e7"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"5.3.0","version":"5.3.0"},"__v":0,"category":{"_id":"588f722bbcace50f0052b9e4","__v":0,"project":"565f5fa26bafd40d0030a064","version":"588f722bbcace50f0052b9e1","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-12-26T05:04:48.794Z","from_sync":false,"order":2,"slug":"samples-and-tutorials","title":"How Tos & Examples"},"parentDoc":null,"user":"565f5f29de5dc50d00acfe9f","project":"565f5fa26bafd40d0030a064","updates":["57e54e91685f7c19007fba4e","57ea8b2b1ac5b01900de38b0"],"next":{"pages":[],"description":""},"createdAt":"2016-06-08T20:13:37.224Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Important\",\n  \"body\": \"In order to run these examples, please make sure you've signed up for a <a target=\\\"_blank\\\" href=\\\"https://dashboard.nanoscale.io/#/registration\\\">nanoscale.io</a> account.\\n\\nThis document will leave you with a fully functional Tasks API. If you want to skip ahead and have the finished product right away, you can download a fully functional copy of this API <a target=\\\"_blank\\\" href=\\\"http://downloads.justapis.com/v5.0.0/tasks.json\\\">here</a>.\"\n}\n[/block]\nThis walkthrough will show you how to create a simple CRUD API on top of a local store collection named Tasks.\n\n## Create Your API\n\nLog into your account and click the 'Build' icon.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/2MYoZjGrSJSDVfqLGpv9_dash.png\",\n        \"dash.png\",\n        \"1000\",\n        \"482\",\n        \"#31404f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThen click the '+ New API...' link. Enter \"Tasks API\" in the 'Name' input field and click 'Save'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/N3oylG1TiKI0anApDYPQ_tasks.png\",\n        \"tasks.png\",\n        \"1371\",\n        \"347\",\n        \"#72975b\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou should see an entry in your API list named \"Tasks API\" with an auto-generated 'Base URL'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/fzHNhZrQL6jAlNM8i0SR_task-entry.png\",\n        \"task-entry.png\",\n        \"1348\",\n        \"48\",\n        \"#86add6\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nGo ahead and click on that. You should see an empty Proxy Endpoints list page.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/4pX4UmC6SyKumiRDYJrJ_proxy.png\",\n        \"proxy.png\",\n        \"1461\",\n        \"787\",\n        \"#405157\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## Create Your Local Store Remote Endpoint\n\nClick on the 'Remote Endpoints' menu item on the left side of the screen. You should see a blank list with the 'HTTP' Remote Endpoint type pre-selected in a new form.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/pnBo55EOT4WxH2NSsjcq_remote.png\",\n        \"remote.png\",\n        \"1184\",\n        \"696\",\n        \"#e7e7e7\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nIn the 'Type' drop-down, choose 'Store'. Let's give it a name of \"Local Store\" and a codename of \"local\". The codename is how this Remote Endpoint will be referenced and used from your JavaScript code in Proxy Endpoints later.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/3JhvtCoqRkyofecrBbGq_store.png\",\n        \"store.png\",\n        \"1173\",\n        \"573\",\n        \"#6e9dc7\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## The Create Task Proxy\n\nGo back to the still empty Proxy Endpoints list. In the new Proxy form, enter \"Create Task\" as the name and click 'Save'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/yltMZ0cpTfu7rnxtekiC_create-task.png\",\n        \"create-task.png\",\n        \"1180\",\n        \"601\",\n        \"#6d9cc5\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou should see a new Proxy Endpoint listed in the list now. Pay attention to the fact that it is listed as 'INACTIVE' in the 'Active' column. By default, all new Proxy Endpoints are inactive. This means that until otherwise specified, this endpoint is *not* publicly available.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/c3Q2piPvTGORdwtlDsrv_create-inactive.png\",\n        \"create-inactive.png\",\n        \"1171\",\n        \"221\",\n        \"#6f8eab\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick into that Proxy Endpoint to get to a more detailed configuration view. Let's turn the proxy 'active' by clicking that checkbox, and let's give it a route with a value of \"/task\". In the Routes section, make sure the 'POST' checkbox is checked and the 'GET' one is *not*. Then click 'Save'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/VvLj4BpmQtGp642cBbhB_create.png\",\n        \"create.png\",\n        \"1189\",\n        \"823\",\n        \"#928d34\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNext, click the check icon in a bubble on the left.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/zKgW9XQFiEk7SaaeCMBA_check.png\",\n        \"check.png\",\n        \"100\",\n        \"94\",\n        \"#4c6484\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThis will take you to the Schema Validations list for this Proxy Endpoints. Schema Validations are JSON Schema definitions that are applied to the requests and responses for a Proxy Endpoint. They are used for generated documentation and for validation. Let's create a new one named 'Task'. Click 'Save'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/5SsWvHrmQuaQFnZjNSRr_task.png\",\n        \"task.png\",\n        \"1195\",\n        \"586\",\n        \"#6082a4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOnce saved, click the 'Task' entry in the list.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/4KqraFPmQJyEnxkkrxHf_task-validation-list.png\",\n        \"task-validation-list.png\",\n        \"1156\",\n        \"590\",\n        \"#627c7b\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou should see two code block areas where you can enter your raw JSON Schema. If both the request and response have the same validation rules, you only have to enter the JSON once and check the 'Response same as request' checkbox.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/kmbhoJX1Tu2NLrurALF7_task-valid.png\",\n        \"task-valid.png\",\n        \"1182\",\n        \"885\",\n        \"#6d86a4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nLet's apply some rules to what our tasks will look like. click into the 'Request schema' code section and enter the following.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"title\\\": \\\"Valid Task\\\",\\n    \\\"type\\\": \\\"object\\\",\\n    \\\"properties\\\": {\\n      \\\"name\\\": {\\n        \\\"type\\\": \\\"string\\\"\\n      },\\n      \\\"priority\\\": {\\n        \\\"description\\\": \\\"Priority of task\\\",\\n        \\\"type\\\": \\\"integer\\\",\\n        \\\"minimum\\\": 0,\\n        \\\"maximum\\\": 10\\n      },\\n      \\\"description\\\": {\\n        \\\"type\\\": \\\"string\\\"\\n      },\\n      \\\"completed\\\": {\\n        \\\"type\\\": \\\"boolean\\\"\\n      }\\n    },\\n    \\\"required\\\": [\\n      \\\"name\\\",\\n      \\\"priority\\\",\\n      \\\"description\\\",\\n      \\\"completed\\\"\\n    ]\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Create Task Schema Validation\"\n    }\n  ]\n}\n[/block]\nThis schema validation tells our Proxy Endpoint that an incoming request *and* outgoing response will:\n\n- be a JSON payload.\n- have a name that is a string.\n- have a priority that is an integer that is between 0 and 10 (inclusive).\n- have a description that is a string.\n- have a completed field that is a boolean value (true or false).\n- require that a valid name, priority, description, and completed field are included in both the incoming and outgoing payload.\n\nIf any of the above rules are violated at request or response time, an appropriate message will be returned to the API client for you.\n\nYour form should look like this:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/mRpA4QywSu2HR5kB5Kbl_validation.png\",\n        \"validation.png\",\n        \"1183\",\n        \"684\",\n        \"#d49b3c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNow click 'Save'.\n\nNext we will add the actual task creation logic. Click the '+' bubble icon on the left.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/pnwiEdzvSdSjNxLsu9Ce_plus.png\",\n        \"plus.png\",\n        \"95\",\n        \"100\",\n        \"#647b93\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nFor this Proxy Endpoint we only require a simple single call to our local store so we can choose the 'Single call' component. Click that.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/iSPg3Q3ERyiasdUyR4Pn_component.png\",\n        \"component.png\",\n        \"1188\",\n        \"575\",\n        \"#506681\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou will see a large form with multiple code blocks and a place to select your Remote Endpoint.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/qzsW02Q7yh2fHvFr7lqQ_single.png\",\n        \"single.png\",\n        \"1188\",\n        \"1203\",\n        \"#6886a8\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThis is where we will write some JavaScript that will handle accepting the incoming request, saving the Task object, and returning the newly created task back to the API client.\n\nSelect 'Local Store' from the Remote Endpoint drop-down.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/1DAftx7pRAGi0NJILUuX_remote.png\",\n        \"remote.png\",\n        \"998\",\n        \"56\",\n        \"#697786\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n In the 'Before request logic' code block, enter the following code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"local.request = new AP.Store.Request();\\nlocal.request.insert(\\\"Tasks\\\", JSON.parse(request.body));\",\n      \"language\": \"javascript\",\n      \"name\": \"Create Task before request\"\n    }\n  ]\n}\n[/block]\nLet's break down the above code.\n\n`local` is the variable that you use because that is the codename you entered for your 'Local Store' Remote Endpoint when you created it.\n\nWe are setting the the `request` object on `local` to an `AP.Store.Request()` because this step is interacting with a `Store` remote endpoint. The `AP.Store.Request` object will have all the necessary properties and functions you need to interact with the desired Remote Endpoint.\n\nLine #2 is where the real work happens. You are telling the AP.Store.Request that you want to insert the JSON parsed value of the incoming request body *into* the `Tasks` collection.\n\nWe can take this shortcut because we created a JSON Schema validation that enforces some JSON rules for us. If the incoming request does not match the Schema Validation defined earlier, it will never get to this point.\n\nWe also do not have to worry about create the `Tasks` collection first. If a collection does not exist at insert time, the nanoscale.io local store will create the collection for you.\n\nThat is all you need in the `Before request logic` block. When this block \"ends\", it will defer to the Remote Endpoint you have selected and pass your `local.request` object along to that Remote Endpoint.\n\nOnce nanoscale.io handles your request and receives a response from the remote endpoint, it will set the response contents on your `local` object and then defer to your `After request logic` code block.\n\nIn this code block we will take the response from the local store and send it back to the HTTP API client. Enter the following code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"response = new AP.HTTP.Response();\\nresponse.setJSONBodyPretty(local.response.data[0]);\",\n      \"language\": \"javascript\",\n      \"name\": \"Create Task after request logic\"\n    }\n  ]\n}\n[/block]\nThe above code initializes a generic Proxy Endpoint `response` with an HTTP response. The HTTP response has everything necessary to talk back to an API client. It has a status code, a body, and headers.\n\nThe `local.response.data` is an array in this case. Since we only care about the record we just created, we can grab the first (and only) element in the array using `local.response.data[0]`. We then set this on the HTTP response object by using the convenience function called `setJSONBodyPretty`. This will take the JSON object and format it for the HTTP response body. It will also set the appropriate content headers and HTTP status code.\n\nYour \" New Single call\" component form should look like:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/vA6ym5XPQdadoeaThLpX_single.png\",\n        \"single.png\",\n        \"1186\",\n        \"1204\",\n        \"#5d83aa\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThat should be all you need to define an endpoints that lets you create Task objects, so let's try it out.\n\nTo see if the endpoint is responding as intended you can exercise it a few different ways.\n\n1 - Use cURL to make a request.\n2 - Use Postman to make a request.\n3 - Use the internal testing mechanism.\n\nIf you want to use an internal tool like cURL, you would issue a command like the following:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X POST -d '{\\\"test\\\": \\\"value\\\"}' https://your-host-1234.justapis.io/task\",\n      \"language\": \"curl\",\n      \"name\": \"Bad POST request with curl\"\n    }\n  ]\n}\n[/block]\nRemember to replace `your-host-1234.justapis.io` with the API base URL value you see in your breadcrumbs.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/2PP07vtTuuTwswvBjdmp_breadcrums.png\",\n        \"breadcrums.png\",\n        \"1015\",\n        \"47\",\n        \"#4d85c4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou should receive the following response:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"- name: name is required - priority: priority is required - description: description is required - completed: completed is required\",\n      \"language\": \"shell\",\n      \"name\": \"cURL bad request response\"\n    }\n  ]\n}\n[/block]\nFor the purposes of this walkthrough though, we will focus on the internal testing mechanism provided by nanoscale.io.\n\nTo use it, click the 'Test' icon in the current 'Create Task Workflow'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/TCCKucdIQDG7CLEMcdaM_tests.png\",\n        \"tests.png\",\n        \"96\",\n        \"98\",\n        \"#4c6484\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nLet's create a matching 'Bad Request' test within the tool. Click 'New Request' and enter the following information:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/NkZG88SdSSupYsBF7qHl_test.png\",\n        \"test.png\",\n        \"1183\",\n        \"833\",\n        \"#7aa99d\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nAll this test does is `POST` the payload `{\"test\": \"value\"}` to the `/task` route. Click 'Save' and then click the new entry in the Tests list. You'll see the full test setup with a few more configuration options that we do not need yet.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/qKjXlWoTtiIqjuLC74pW_test.png\",\n        \"test.png\",\n        \"1176\",\n        \"1178\",\n        \"#6e849c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Execute' on the bottom of the screen to run this against your endpoint. You'll see the following error returned.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/tEUytITU2kHKq27uKQt8_fail.png\",\n        \"fail.png\",\n        \"1024\",\n        \"428\",\n        \"#931720\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can see that the request failed with the same response we received when using cURL. You can also see the included server log that reflects the lifecycle of this request.\n\nLet's go build a valid request payload to create our first `Task` object.\n\nClick back to the 'Tests' list and click 'New test'. Enter the following data into the `Body` field of the form:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"name\\\": \\\"Good Request\\\",\\n    \\\"priority\\\": 1,\\n    \\\"description\\\": \\\"Show users how to create a valid task.\\\",\\n    \\\"completed\\\": true\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Good Create Task request\"\n    }\n  ]\n}\n[/block]\nYour form should look like:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/fxO7FhIQSveIlcOy9VvO_good.png\",\n        \"good.png\",\n        \"1031\",\n        \"589\",\n        \"#627b3d\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Save'. Your test request is ready to execute. Click into the newly created test. Go ahead an click 'Execute' at the bottom of the screen. You should see a `200` response come back with your newly created Task object.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/u3nyiNX4QAODr7MTauSh_executed.png\",\n        \"executed.png\",\n        \"1015\",\n        \"635\",\n        \"#66414a\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nIf we go look at the Collections view we should see a newly created 'Tasks' collection and our 'Task' object. You can get there by either clicking the little 'Manage' icon on the far left nav view of the screen.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/pGw1fHE6S42VTLlsTreQ_left.png\",\n        \"left.png\",\n        \"260\",\n        \"316\",\n        \"#e95c38\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can get to the same view from the main dashboard page via the large 'Manage' bubble.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/dEHmML4CR06NpXzIQkac_manage.png\",\n        \"manage.png\",\n        \"259\",\n        \"352\",\n        \"#cc9459\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOnce in the 'Collections' view, you'll see all of your collections and the objects in those collections. By default the first collection is selected.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/rDdMpmOSSTm3SgxwDJcd_collections.png\",\n        \"collections.png\",\n        \"1323\",\n        \"449\",\n        \"#d04a6d\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nCongratulations! You've just built a simple API that actually persists data.\n\nThe next few sections will show you how to build on top of this API. They won't be as in-depth as the previous section and will assume an understanding of navigation and key terms illustrated above.\n\n## Listing Tasks\n\nWhat good is creating tasks if you can't query them later?\n\nGo create a new Proxy Endpoint named \"List Tasks\".\n\nAfter creating it and clicking into the new Proxy Endpoint, mark it as 'Active' and set a route for `/tasks` and choose the `GET` method.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/SvAsLAP3SZeMdci9sCqW_list.png\",\n        \"list.png\",\n        \"1179\",\n        \"820\",\n        \"#d79e4c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNow let's add a 'Simple component' to this endpoint.\n\nSet the 'Remote endpoint' to 'Local Store' and enter the following for your 'Before request logic':\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"local.request = new AP.Store.Request();\\nif (request.params.query === \\\"complete\\\") {\\n  local.request.select(\\\"Tasks\\\", \\\"completed = $1\\\", true);\\n} else if (request.params.query === \\\"incomplete\\\") {\\n  local.request.select(\\\"Tasks\\\", \\\"completed = $1\\\", false);\\n} else {\\n  local.request.select(\\\"Tasks\\\", \\\"true\\\");\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"List Tasks Before request logic\"\n    }\n  ]\n}\n[/block]\nThe code above takes the incoming request and does the following:\n\n1. If a query parameter exists and it is set to `complete` then tasks that have `completed` set to `true` are returned.\n2. If a query parameter exists and it is set to `incomplete` then tasks that have `completed` set to `false` are returned.\n3. If none of the above are true, just return all tasks.\n\nSet the following for your 'After request logic':\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"response = new AP.HTTP.Response();\\nresponse.setJSONBodyPretty(local.response.data);\",\n      \"language\": \"javascript\",\n      \"name\": \"List Tasks After request logic\"\n    }\n  ]\n}\n[/block]\nSince we are returning a list of results, we just set the entire `local.response.data` set on the response body.\n\nLet's go create another test to make sure our List endpoint actually works.\n\nName it \"List all Tasks\", set the method to `GET`, and choose the `/tasks` route. Click 'Save' and then 'Execute'. You should see the following:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/GdK1dosGQEiYjBWVXLm3_list.png\",\n        \"list.png\",\n        \"1164\",\n        \"1256\",\n        \"#9b9c53\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can also view the result in a browser by visiting something like `https://your-host-1234.justapis.io/tasks`. The hostname will depend on the Base URL value that was generated for your API.\n\n## Getting Individual Tasks\n\nAnother important action you'll probably want to perform is getting an individual task by its `id`.\n\nGo create another Proxy Endpoint named \"Get Task\". Click into that new endpoint and make sure it is marked as 'Active'. Create a `GET` method route with the following value: `/tasks/{id}`. This tells our Proxy that request coming in will have a parameter in the URL after the `/tasks/` named id. You can grab that `id` in your custom code using `request.params.id`. Your Proxy Endpoint form should look like:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/MsrTELcSrKzASH3cu4NT_get-task.png\",\n        \"get-task.png\",\n        \"1180\",\n        \"819\",\n        \"#de983b\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nNow add another 'Single component' for this endpoint. Choose 'Local Store' for the Remote Endpoint.\n\nEnter the following for the 'Before request logic':\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"local.request = new AP.Store.Request();\\nlocal.request.select(\\\"Tasks\\\", parseInt(request.params.id));\",\n      \"language\": \"javascript\",\n      \"name\": \"Get Task Before request logic\"\n    }\n  ]\n}\n[/block]\nThe above code will issue a `select` to the `Tasks` collection and do a lookup by `$id`.\n\nWe run `parseInt()` on the incoming request ID to convert it from a `string` to an `integer`.\n\nEnter the following for the 'After request logic':\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"response = new AP.HTTP.Response();\\nif (local.response.data === null) {\\n  response.body = null;\\n  response.statusCode = 404;\\n} else {\\n  response.setJSONBodyPretty(local.response.data[0]);\\n}\",\n      \"language\": \"javascript\",\n      \"name\": \"Get Task After request logic\"\n    }\n  ]\n}\n[/block]\nThe above code checks the local store response for data. If none exists, a `404` is returned to the API client. If data exists, the individual result it pulled from the result set and placed into the HTTP response body and returned to the client.\n\nLet's create tests to exercise two scenarios:\n\n1. A non-existent Task object ID.\n2. An existing Task object ID.\n\nCreate a new test and name is \"Get Non-Existent Task\". Choose the `GET` method and the `/tasks/{id}` route.\n\nCreate an argument named `id` with a value of `99999999`. Save it and hit 'Execute'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/FqC1vJWaQeelYsa1aqWZ_no-task.png\",\n        \"no-task.png\",\n        \"1165\",\n        \"1317\",\n        \"#b89d4f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can see a `404` response code with an empty response body. This is because no object with the id `99999999` currently exists.\n\nNow go create another test named \"Get Existing Task\". Enter the same settings are the non-existent task test, but this time enter the `id` that got returned when you created a new Task object. We will use `42` for ours. Hit 'Execute'.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/sio2pbCSGKaLZ1FPt89f_existing.png\",\n        \"existing.png\",\n        \"1017\",\n        \"1342\",\n        \"#dc7494\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou can see the response now contains our desired Task object.\n\nNext, we need to be able to update our object.\n\n## Updating a Task Object\n\nThis should be easy now that you've built a few other proxies. First, create a new Proxy Endpoint named \"Update Task\". Make sure you mark it active. Since this will be an action on an individual resource, the route will be the same as the previous `GET` route. Enter `/task/{id}` for the route value, but this time choose `PUT` as the method.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/BQrMX95cSiaZ84GpySVq_update.png\",\n        \"update.png\",\n        \"1184\",\n        \"815\",\n        \"#d4983f\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Save' and go add a 'Schema Validation'.\n\nCall this validation 'Task' and give it the same JSON Schema contents as the Create Task Proxy Endpoint validation schema from earlier.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"title\\\": \\\"Valid Task\\\",\\n    \\\"type\\\": \\\"object\\\",\\n    \\\"properties\\\": {\\n      \\\"name\\\": {\\n        \\\"type\\\": \\\"string\\\"\\n      },\\n      \\\"priority\\\": {\\n        \\\"description\\\": \\\"Priority of task\\\",\\n        \\\"type\\\": \\\"integer\\\",\\n        \\\"minimum\\\": 0,\\n        \\\"maximum\\\": 10\\n      },\\n      \\\"description\\\": {\\n        \\\"type\\\": \\\"string\\\"\\n      },\\n      \\\"completed\\\": {\\n        \\\"type\\\": \\\"boolean\\\"\\n      }\\n    },\\n    \\\"required\\\": [\\n      \\\"name\\\",\\n      \\\"priority\\\",\\n      \\\"description\\\",\\n      \\\"completed\\\"\\n    ]\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Update Task Schema validation\"\n    }\n  ]\n}\n[/block]\nNow go create a new 'Single call component'.\n\nFor the \"Remote endpoint\" choose \"Local Store\" again.\n\nEnter the following code into the 'Before request logic' code block:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"local.request = new AP.Store.Request();\\nlocal.request.update(\\\"Tasks\\\", parseInt(request.params.id), JSON.parse(request.body));\",\n      \"language\": \"javascript\",\n      \"name\": \"Update Task Before request logic\"\n    }\n  ]\n}\n[/block]\nThe above code functions just like the `insert` code same from earlier. The only difference here is that we are calling the `update` method on our local store *and* we are not also passing the corresponding object `id`. This tells the local store to update the object with `id` matching `request.params.id` with the values from `JSON.parse(request.body)`.\n\nEnter the following for the 'After request logic':\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"response = new AP.HTTP.Response();\\nresponse.setJSONBodyPretty(local.response.data[0]);\\n\",\n      \"language\": \"javascript\",\n      \"name\": \"Update Task After request logic\"\n    }\n  ]\n}\n[/block]\nThe above code does exactly the same as the code did in the 'Create Task After request logic' code block.\n\nWe can test it quickly by creating a new test named \"Update Task\". Use the following for the body payload:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n    \\\"completed\\\": true,\\n    \\\"description\\\": \\\"Show users how to update a valid task.\\\",\\n    \\\"name\\\": \\\"Good Request\\\",\\n    \\\"priority\\\": 1\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Update Task body payload\"\n    }\n  ]\n}\n[/block]\nYour new test form should look like:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/8S50LWFuRmu5kTasIiHP_update-test.png\",\n        \"update-test.png\",\n        \"1180\",\n        \"817\",\n        \"#4c6481\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Save' and select your newly created test. Go ahead and create an argument named `id` with a value that matches an existing Task object in your Tasks collection. We used `42`. Save and click 'Execute'. You should get the updated Task object back in the payload.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ZSA09rV2ReqzDyzl4tBk_task-updated.png\",\n        \"task-updated.png\",\n        \"1251\",\n        \"1279\",\n        \"#4a6282\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nYou've successfully updated a Task object! What's next?\n\n## Deleting a Task Object\n\nYou guessed it! Time to cleanup. This should be pretty easy at this point.\n\nGo create new Proxy Endpoint. Name it \"Delete Task\". Save it and select it.\n\nMake sure it is marked 'Active'. Enter `/task/{id}` for the routes (again this is acting on a singular resource), but this time choose the `DELETE` checkbox for the method.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/PmC6tdLRCGZ6A6l3Vtfk_delete.png\",\n        \"delete.png\",\n        \"1193\",\n        \"818\",\n        \"#951c27\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Save' and go add a new 'Single call component'.\n\nAgain, choose the 'Local Store' as the 'Remote endpoint'.\n\nEnter the following for the 'Before request logic' code block:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"local.request = new AP.Store.Request();\\nlocal.request.delete(\\\"Tasks\\\", parseInt(request.params.id));\",\n      \"language\": \"javascript\",\n      \"name\": \"Delete Task Before request logic\"\n    }\n  ]\n}\n[/block]\nThe above code is very similar to the `select` operation. This time, however, it is destructive. This will delete an object from the `Tasks` collection that has `request.params.id` as the `$id` value.\n\nEnter the following for your 'After request logic' section:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"response = new AP.HTTP.Response();\\nif (local.response.data === null) {\\n  response.body = null;\\n  response.statusCode = 404;\\n} else {\\n  response.statusCode = 204;\\n}\",\n      \"language\": \"json\",\n      \"name\": \"Delete Task After request logic\"\n    }\n  ]\n}\n[/block]\nThe above code does two things:\n\n1. Return a `404` if nothing matched the `delete` operation.\n2. Return a `204` if the `delete` operation matched an existing object in the `Tasks` collection.\n\nYour new 'Single call component' form should look like:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/24EjH6aTAe1WZWhOk3l0_delete-call.png\",\n        \"delete-call.png\",\n        \"1180\",\n        \"1204\",\n        \"#b67054\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Save'. Now, let's test it!\n\nCreate a new test named \"Delete Task\". Choose the `DELETE` method and the `/task/{id}` route. We don't need a body payload for this operation.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/hYboZ9ngQyc6eaBpNkAA_delete-test.png\",\n        \"delete-test.png\",\n        \"1183\",\n        \"756\",\n        \"#587697\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nClick 'Save' and select the newly created test. All you need to do is add an argument with a name of `id` and a value of your previous Task object. We will use `42` again since it exists in our account. Click 'Save' and then click 'Execute'. You should see the following:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/dMYgVsKYS3CZsiblyblN_deleted.png\",\n        \"deleted.png\",\n        \"1160\",\n        \"1315\",\n        \"#5c6e73\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nGo check your `Tasks` collection. You should be missing an object with this `id`.\n\nVoilà! You just built a fully functional Tasks API.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Tasks API\",\n  \"body\": \"The fully functional source for this Tasks API is available for download <a target=\\\"_blank\\\" href=\\\"http://downloads.justapis.com/v5.0.0/tasks.json\\\">here</a>.\\n\\nYou can import the API into your account and have it immediately ready for use.\"\n}\n[/block]","excerpt":"","slug":"building-a-tasks-api","type":"basic","title":"Building a Tasks API"}

Building a Tasks API


[block:callout] { "type": "info", "title": "Important", "body": "In order to run these examples, please make sure you've signed up for a <a target=\"_blank\" href=\"https://dashboard.nanoscale.io/#/registration\">nanoscale.io</a> account.\n\nThis document will leave you with a fully functional Tasks API. If you want to skip ahead and have the finished product right away, you can download a fully functional copy of this API <a target=\"_blank\" href=\"http://downloads.justapis.com/v5.0.0/tasks.json\">here</a>." } [/block] This walkthrough will show you how to create a simple CRUD API on top of a local store collection named Tasks. ## Create Your API Log into your account and click the 'Build' icon. [block:image] { "images": [ { "image": [ "https://files.readme.io/2MYoZjGrSJSDVfqLGpv9_dash.png", "dash.png", "1000", "482", "#31404f", "" ] } ] } [/block] Then click the '+ New API...' link. Enter "Tasks API" in the 'Name' input field and click 'Save'. [block:image] { "images": [ { "image": [ "https://files.readme.io/N3oylG1TiKI0anApDYPQ_tasks.png", "tasks.png", "1371", "347", "#72975b", "" ] } ] } [/block] You should see an entry in your API list named "Tasks API" with an auto-generated 'Base URL'. [block:image] { "images": [ { "image": [ "https://files.readme.io/fzHNhZrQL6jAlNM8i0SR_task-entry.png", "task-entry.png", "1348", "48", "#86add6", "" ] } ] } [/block] Go ahead and click on that. You should see an empty Proxy Endpoints list page. [block:image] { "images": [ { "image": [ "https://files.readme.io/4pX4UmC6SyKumiRDYJrJ_proxy.png", "proxy.png", "1461", "787", "#405157", "" ] } ] } [/block] ## Create Your Local Store Remote Endpoint Click on the 'Remote Endpoints' menu item on the left side of the screen. You should see a blank list with the 'HTTP' Remote Endpoint type pre-selected in a new form. [block:image] { "images": [ { "image": [ "https://files.readme.io/pnBo55EOT4WxH2NSsjcq_remote.png", "remote.png", "1184", "696", "#e7e7e7", "" ] } ] } [/block] In the 'Type' drop-down, choose 'Store'. Let's give it a name of "Local Store" and a codename of "local". The codename is how this Remote Endpoint will be referenced and used from your JavaScript code in Proxy Endpoints later. [block:image] { "images": [ { "image": [ "https://files.readme.io/3JhvtCoqRkyofecrBbGq_store.png", "store.png", "1173", "573", "#6e9dc7", "" ] } ] } [/block] ## The Create Task Proxy Go back to the still empty Proxy Endpoints list. In the new Proxy form, enter "Create Task" as the name and click 'Save'. [block:image] { "images": [ { "image": [ "https://files.readme.io/yltMZ0cpTfu7rnxtekiC_create-task.png", "create-task.png", "1180", "601", "#6d9cc5", "" ] } ] } [/block] You should see a new Proxy Endpoint listed in the list now. Pay attention to the fact that it is listed as 'INACTIVE' in the 'Active' column. By default, all new Proxy Endpoints are inactive. This means that until otherwise specified, this endpoint is *not* publicly available. [block:image] { "images": [ { "image": [ "https://files.readme.io/c3Q2piPvTGORdwtlDsrv_create-inactive.png", "create-inactive.png", "1171", "221", "#6f8eab", "" ] } ] } [/block] Click into that Proxy Endpoint to get to a more detailed configuration view. Let's turn the proxy 'active' by clicking that checkbox, and let's give it a route with a value of "/task". In the Routes section, make sure the 'POST' checkbox is checked and the 'GET' one is *not*. Then click 'Save'. [block:image] { "images": [ { "image": [ "https://files.readme.io/VvLj4BpmQtGp642cBbhB_create.png", "create.png", "1189", "823", "#928d34", "" ] } ] } [/block] Next, click the check icon in a bubble on the left. [block:image] { "images": [ { "image": [ "https://files.readme.io/zKgW9XQFiEk7SaaeCMBA_check.png", "check.png", "100", "94", "#4c6484", "" ] } ] } [/block] This will take you to the Schema Validations list for this Proxy Endpoints. Schema Validations are JSON Schema definitions that are applied to the requests and responses for a Proxy Endpoint. They are used for generated documentation and for validation. Let's create a new one named 'Task'. Click 'Save'. [block:image] { "images": [ { "image": [ "https://files.readme.io/5SsWvHrmQuaQFnZjNSRr_task.png", "task.png", "1195", "586", "#6082a4", "" ] } ] } [/block] Once saved, click the 'Task' entry in the list. [block:image] { "images": [ { "image": [ "https://files.readme.io/4KqraFPmQJyEnxkkrxHf_task-validation-list.png", "task-validation-list.png", "1156", "590", "#627c7b", "" ] } ] } [/block] You should see two code block areas where you can enter your raw JSON Schema. If both the request and response have the same validation rules, you only have to enter the JSON once and check the 'Response same as request' checkbox. [block:image] { "images": [ { "image": [ "https://files.readme.io/kmbhoJX1Tu2NLrurALF7_task-valid.png", "task-valid.png", "1182", "885", "#6d86a4", "" ] } ] } [/block] Let's apply some rules to what our tasks will look like. click into the 'Request schema' code section and enter the following. [block:code] { "codes": [ { "code": "{\n \"title\": \"Valid Task\",\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"priority\": {\n \"description\": \"Priority of task\",\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 10\n },\n \"description\": {\n \"type\": \"string\"\n },\n \"completed\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"name\",\n \"priority\",\n \"description\",\n \"completed\"\n ]\n}", "language": "json", "name": "Create Task Schema Validation" } ] } [/block] This schema validation tells our Proxy Endpoint that an incoming request *and* outgoing response will: - be a JSON payload. - have a name that is a string. - have a priority that is an integer that is between 0 and 10 (inclusive). - have a description that is a string. - have a completed field that is a boolean value (true or false). - require that a valid name, priority, description, and completed field are included in both the incoming and outgoing payload. If any of the above rules are violated at request or response time, an appropriate message will be returned to the API client for you. Your form should look like this: [block:image] { "images": [ { "image": [ "https://files.readme.io/mRpA4QywSu2HR5kB5Kbl_validation.png", "validation.png", "1183", "684", "#d49b3c", "" ] } ] } [/block] Now click 'Save'. Next we will add the actual task creation logic. Click the '+' bubble icon on the left. [block:image] { "images": [ { "image": [ "https://files.readme.io/pnwiEdzvSdSjNxLsu9Ce_plus.png", "plus.png", "95", "100", "#647b93", "" ] } ] } [/block] For this Proxy Endpoint we only require a simple single call to our local store so we can choose the 'Single call' component. Click that. [block:image] { "images": [ { "image": [ "https://files.readme.io/iSPg3Q3ERyiasdUyR4Pn_component.png", "component.png", "1188", "575", "#506681", "" ] } ] } [/block] You will see a large form with multiple code blocks and a place to select your Remote Endpoint. [block:image] { "images": [ { "image": [ "https://files.readme.io/qzsW02Q7yh2fHvFr7lqQ_single.png", "single.png", "1188", "1203", "#6886a8", "" ] } ] } [/block] This is where we will write some JavaScript that will handle accepting the incoming request, saving the Task object, and returning the newly created task back to the API client. Select 'Local Store' from the Remote Endpoint drop-down. [block:image] { "images": [ { "image": [ "https://files.readme.io/1DAftx7pRAGi0NJILUuX_remote.png", "remote.png", "998", "56", "#697786", "" ] } ] } [/block] In the 'Before request logic' code block, enter the following code: [block:code] { "codes": [ { "code": "local.request = new AP.Store.Request();\nlocal.request.insert(\"Tasks\", JSON.parse(request.body));", "language": "javascript", "name": "Create Task before request" } ] } [/block] Let's break down the above code. `local` is the variable that you use because that is the codename you entered for your 'Local Store' Remote Endpoint when you created it. We are setting the the `request` object on `local` to an `AP.Store.Request()` because this step is interacting with a `Store` remote endpoint. The `AP.Store.Request` object will have all the necessary properties and functions you need to interact with the desired Remote Endpoint. Line #2 is where the real work happens. You are telling the AP.Store.Request that you want to insert the JSON parsed value of the incoming request body *into* the `Tasks` collection. We can take this shortcut because we created a JSON Schema validation that enforces some JSON rules for us. If the incoming request does not match the Schema Validation defined earlier, it will never get to this point. We also do not have to worry about create the `Tasks` collection first. If a collection does not exist at insert time, the nanoscale.io local store will create the collection for you. That is all you need in the `Before request logic` block. When this block "ends", it will defer to the Remote Endpoint you have selected and pass your `local.request` object along to that Remote Endpoint. Once nanoscale.io handles your request and receives a response from the remote endpoint, it will set the response contents on your `local` object and then defer to your `After request logic` code block. In this code block we will take the response from the local store and send it back to the HTTP API client. Enter the following code: [block:code] { "codes": [ { "code": "response = new AP.HTTP.Response();\nresponse.setJSONBodyPretty(local.response.data[0]);", "language": "javascript", "name": "Create Task after request logic" } ] } [/block] The above code initializes a generic Proxy Endpoint `response` with an HTTP response. The HTTP response has everything necessary to talk back to an API client. It has a status code, a body, and headers. The `local.response.data` is an array in this case. Since we only care about the record we just created, we can grab the first (and only) element in the array using `local.response.data[0]`. We then set this on the HTTP response object by using the convenience function called `setJSONBodyPretty`. This will take the JSON object and format it for the HTTP response body. It will also set the appropriate content headers and HTTP status code. Your " New Single call" component form should look like: [block:image] { "images": [ { "image": [ "https://files.readme.io/vA6ym5XPQdadoeaThLpX_single.png", "single.png", "1186", "1204", "#5d83aa", "" ] } ] } [/block] That should be all you need to define an endpoints that lets you create Task objects, so let's try it out. To see if the endpoint is responding as intended you can exercise it a few different ways. 1 - Use cURL to make a request. 2 - Use Postman to make a request. 3 - Use the internal testing mechanism. If you want to use an internal tool like cURL, you would issue a command like the following: [block:code] { "codes": [ { "code": "curl -X POST -d '{\"test\": \"value\"}' https://your-host-1234.justapis.io/task", "language": "curl", "name": "Bad POST request with curl" } ] } [/block] Remember to replace `your-host-1234.justapis.io` with the API base URL value you see in your breadcrumbs. [block:image] { "images": [ { "image": [ "https://files.readme.io/2PP07vtTuuTwswvBjdmp_breadcrums.png", "breadcrums.png", "1015", "47", "#4d85c4", "" ] } ] } [/block] You should receive the following response: [block:code] { "codes": [ { "code": "- name: name is required - priority: priority is required - description: description is required - completed: completed is required", "language": "shell", "name": "cURL bad request response" } ] } [/block] For the purposes of this walkthrough though, we will focus on the internal testing mechanism provided by nanoscale.io. To use it, click the 'Test' icon in the current 'Create Task Workflow'. [block:image] { "images": [ { "image": [ "https://files.readme.io/TCCKucdIQDG7CLEMcdaM_tests.png", "tests.png", "96", "98", "#4c6484", "" ] } ] } [/block] Let's create a matching 'Bad Request' test within the tool. Click 'New Request' and enter the following information: [block:image] { "images": [ { "image": [ "https://files.readme.io/NkZG88SdSSupYsBF7qHl_test.png", "test.png", "1183", "833", "#7aa99d", "" ] } ] } [/block] All this test does is `POST` the payload `{"test": "value"}` to the `/task` route. Click 'Save' and then click the new entry in the Tests list. You'll see the full test setup with a few more configuration options that we do not need yet. [block:image] { "images": [ { "image": [ "https://files.readme.io/qKjXlWoTtiIqjuLC74pW_test.png", "test.png", "1176", "1178", "#6e849c", "" ] } ] } [/block] Click 'Execute' on the bottom of the screen to run this against your endpoint. You'll see the following error returned. [block:image] { "images": [ { "image": [ "https://files.readme.io/tEUytITU2kHKq27uKQt8_fail.png", "fail.png", "1024", "428", "#931720", "" ] } ] } [/block] You can see that the request failed with the same response we received when using cURL. You can also see the included server log that reflects the lifecycle of this request. Let's go build a valid request payload to create our first `Task` object. Click back to the 'Tests' list and click 'New test'. Enter the following data into the `Body` field of the form: [block:code] { "codes": [ { "code": "{\n \"name\": \"Good Request\",\n \"priority\": 1,\n \"description\": \"Show users how to create a valid task.\",\n \"completed\": true\n}", "language": "json", "name": "Good Create Task request" } ] } [/block] Your form should look like: [block:image] { "images": [ { "image": [ "https://files.readme.io/fxO7FhIQSveIlcOy9VvO_good.png", "good.png", "1031", "589", "#627b3d", "" ] } ] } [/block] Click 'Save'. Your test request is ready to execute. Click into the newly created test. Go ahead an click 'Execute' at the bottom of the screen. You should see a `200` response come back with your newly created Task object. [block:image] { "images": [ { "image": [ "https://files.readme.io/u3nyiNX4QAODr7MTauSh_executed.png", "executed.png", "1015", "635", "#66414a", "" ] } ] } [/block] If we go look at the Collections view we should see a newly created 'Tasks' collection and our 'Task' object. You can get there by either clicking the little 'Manage' icon on the far left nav view of the screen. [block:image] { "images": [ { "image": [ "https://files.readme.io/pGw1fHE6S42VTLlsTreQ_left.png", "left.png", "260", "316", "#e95c38", "" ] } ] } [/block] You can get to the same view from the main dashboard page via the large 'Manage' bubble. [block:image] { "images": [ { "image": [ "https://files.readme.io/dEHmML4CR06NpXzIQkac_manage.png", "manage.png", "259", "352", "#cc9459", "" ] } ] } [/block] Once in the 'Collections' view, you'll see all of your collections and the objects in those collections. By default the first collection is selected. [block:image] { "images": [ { "image": [ "https://files.readme.io/rDdMpmOSSTm3SgxwDJcd_collections.png", "collections.png", "1323", "449", "#d04a6d", "" ] } ] } [/block] Congratulations! You've just built a simple API that actually persists data. The next few sections will show you how to build on top of this API. They won't be as in-depth as the previous section and will assume an understanding of navigation and key terms illustrated above. ## Listing Tasks What good is creating tasks if you can't query them later? Go create a new Proxy Endpoint named "List Tasks". After creating it and clicking into the new Proxy Endpoint, mark it as 'Active' and set a route for `/tasks` and choose the `GET` method. [block:image] { "images": [ { "image": [ "https://files.readme.io/SvAsLAP3SZeMdci9sCqW_list.png", "list.png", "1179", "820", "#d79e4c", "" ] } ] } [/block] Now let's add a 'Simple component' to this endpoint. Set the 'Remote endpoint' to 'Local Store' and enter the following for your 'Before request logic': [block:code] { "codes": [ { "code": "local.request = new AP.Store.Request();\nif (request.params.query === \"complete\") {\n local.request.select(\"Tasks\", \"completed = $1\", true);\n} else if (request.params.query === \"incomplete\") {\n local.request.select(\"Tasks\", \"completed = $1\", false);\n} else {\n local.request.select(\"Tasks\", \"true\");\n}", "language": "javascript", "name": "List Tasks Before request logic" } ] } [/block] The code above takes the incoming request and does the following: 1. If a query parameter exists and it is set to `complete` then tasks that have `completed` set to `true` are returned. 2. If a query parameter exists and it is set to `incomplete` then tasks that have `completed` set to `false` are returned. 3. If none of the above are true, just return all tasks. Set the following for your 'After request logic': [block:code] { "codes": [ { "code": "response = new AP.HTTP.Response();\nresponse.setJSONBodyPretty(local.response.data);", "language": "javascript", "name": "List Tasks After request logic" } ] } [/block] Since we are returning a list of results, we just set the entire `local.response.data` set on the response body. Let's go create another test to make sure our List endpoint actually works. Name it "List all Tasks", set the method to `GET`, and choose the `/tasks` route. Click 'Save' and then 'Execute'. You should see the following: [block:image] { "images": [ { "image": [ "https://files.readme.io/GdK1dosGQEiYjBWVXLm3_list.png", "list.png", "1164", "1256", "#9b9c53", "" ] } ] } [/block] You can also view the result in a browser by visiting something like `https://your-host-1234.justapis.io/tasks`. The hostname will depend on the Base URL value that was generated for your API. ## Getting Individual Tasks Another important action you'll probably want to perform is getting an individual task by its `id`. Go create another Proxy Endpoint named "Get Task". Click into that new endpoint and make sure it is marked as 'Active'. Create a `GET` method route with the following value: `/tasks/{id}`. This tells our Proxy that request coming in will have a parameter in the URL after the `/tasks/` named id. You can grab that `id` in your custom code using `request.params.id`. Your Proxy Endpoint form should look like: [block:image] { "images": [ { "image": [ "https://files.readme.io/MsrTELcSrKzASH3cu4NT_get-task.png", "get-task.png", "1180", "819", "#de983b", "" ] } ] } [/block] Now add another 'Single component' for this endpoint. Choose 'Local Store' for the Remote Endpoint. Enter the following for the 'Before request logic': [block:code] { "codes": [ { "code": "local.request = new AP.Store.Request();\nlocal.request.select(\"Tasks\", parseInt(request.params.id));", "language": "javascript", "name": "Get Task Before request logic" } ] } [/block] The above code will issue a `select` to the `Tasks` collection and do a lookup by `$id`. We run `parseInt()` on the incoming request ID to convert it from a `string` to an `integer`. Enter the following for the 'After request logic': [block:code] { "codes": [ { "code": "response = new AP.HTTP.Response();\nif (local.response.data === null) {\n response.body = null;\n response.statusCode = 404;\n} else {\n response.setJSONBodyPretty(local.response.data[0]);\n}", "language": "javascript", "name": "Get Task After request logic" } ] } [/block] The above code checks the local store response for data. If none exists, a `404` is returned to the API client. If data exists, the individual result it pulled from the result set and placed into the HTTP response body and returned to the client. Let's create tests to exercise two scenarios: 1. A non-existent Task object ID. 2. An existing Task object ID. Create a new test and name is "Get Non-Existent Task". Choose the `GET` method and the `/tasks/{id}` route. Create an argument named `id` with a value of `99999999`. Save it and hit 'Execute'. [block:image] { "images": [ { "image": [ "https://files.readme.io/FqC1vJWaQeelYsa1aqWZ_no-task.png", "no-task.png", "1165", "1317", "#b89d4f", "" ] } ] } [/block] You can see a `404` response code with an empty response body. This is because no object with the id `99999999` currently exists. Now go create another test named "Get Existing Task". Enter the same settings are the non-existent task test, but this time enter the `id` that got returned when you created a new Task object. We will use `42` for ours. Hit 'Execute'. [block:image] { "images": [ { "image": [ "https://files.readme.io/sio2pbCSGKaLZ1FPt89f_existing.png", "existing.png", "1017", "1342", "#dc7494", "" ] } ] } [/block] You can see the response now contains our desired Task object. Next, we need to be able to update our object. ## Updating a Task Object This should be easy now that you've built a few other proxies. First, create a new Proxy Endpoint named "Update Task". Make sure you mark it active. Since this will be an action on an individual resource, the route will be the same as the previous `GET` route. Enter `/task/{id}` for the route value, but this time choose `PUT` as the method. [block:image] { "images": [ { "image": [ "https://files.readme.io/BQrMX95cSiaZ84GpySVq_update.png", "update.png", "1184", "815", "#d4983f", "" ] } ] } [/block] Click 'Save' and go add a 'Schema Validation'. Call this validation 'Task' and give it the same JSON Schema contents as the Create Task Proxy Endpoint validation schema from earlier. [block:code] { "codes": [ { "code": "{\n \"title\": \"Valid Task\",\n \"type\": \"object\",\n \"properties\": {\n \"name\": {\n \"type\": \"string\"\n },\n \"priority\": {\n \"description\": \"Priority of task\",\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 10\n },\n \"description\": {\n \"type\": \"string\"\n },\n \"completed\": {\n \"type\": \"boolean\"\n }\n },\n \"required\": [\n \"name\",\n \"priority\",\n \"description\",\n \"completed\"\n ]\n}", "language": "json", "name": "Update Task Schema validation" } ] } [/block] Now go create a new 'Single call component'. For the "Remote endpoint" choose "Local Store" again. Enter the following code into the 'Before request logic' code block: [block:code] { "codes": [ { "code": "local.request = new AP.Store.Request();\nlocal.request.update(\"Tasks\", parseInt(request.params.id), JSON.parse(request.body));", "language": "javascript", "name": "Update Task Before request logic" } ] } [/block] The above code functions just like the `insert` code same from earlier. The only difference here is that we are calling the `update` method on our local store *and* we are not also passing the corresponding object `id`. This tells the local store to update the object with `id` matching `request.params.id` with the values from `JSON.parse(request.body)`. Enter the following for the 'After request logic': [block:code] { "codes": [ { "code": "response = new AP.HTTP.Response();\nresponse.setJSONBodyPretty(local.response.data[0]);\n", "language": "javascript", "name": "Update Task After request logic" } ] } [/block] The above code does exactly the same as the code did in the 'Create Task After request logic' code block. We can test it quickly by creating a new test named "Update Task". Use the following for the body payload: [block:code] { "codes": [ { "code": "{\n \"completed\": true,\n \"description\": \"Show users how to update a valid task.\",\n \"name\": \"Good Request\",\n \"priority\": 1\n}", "language": "json", "name": "Update Task body payload" } ] } [/block] Your new test form should look like: [block:image] { "images": [ { "image": [ "https://files.readme.io/8S50LWFuRmu5kTasIiHP_update-test.png", "update-test.png", "1180", "817", "#4c6481", "" ] } ] } [/block] Click 'Save' and select your newly created test. Go ahead and create an argument named `id` with a value that matches an existing Task object in your Tasks collection. We used `42`. Save and click 'Execute'. You should get the updated Task object back in the payload. [block:image] { "images": [ { "image": [ "https://files.readme.io/ZSA09rV2ReqzDyzl4tBk_task-updated.png", "task-updated.png", "1251", "1279", "#4a6282", "" ] } ] } [/block] You've successfully updated a Task object! What's next? ## Deleting a Task Object You guessed it! Time to cleanup. This should be pretty easy at this point. Go create new Proxy Endpoint. Name it "Delete Task". Save it and select it. Make sure it is marked 'Active'. Enter `/task/{id}` for the routes (again this is acting on a singular resource), but this time choose the `DELETE` checkbox for the method. [block:image] { "images": [ { "image": [ "https://files.readme.io/PmC6tdLRCGZ6A6l3Vtfk_delete.png", "delete.png", "1193", "818", "#951c27", "" ] } ] } [/block] Click 'Save' and go add a new 'Single call component'. Again, choose the 'Local Store' as the 'Remote endpoint'. Enter the following for the 'Before request logic' code block: [block:code] { "codes": [ { "code": "local.request = new AP.Store.Request();\nlocal.request.delete(\"Tasks\", parseInt(request.params.id));", "language": "javascript", "name": "Delete Task Before request logic" } ] } [/block] The above code is very similar to the `select` operation. This time, however, it is destructive. This will delete an object from the `Tasks` collection that has `request.params.id` as the `$id` value. Enter the following for your 'After request logic' section: [block:code] { "codes": [ { "code": "response = new AP.HTTP.Response();\nif (local.response.data === null) {\n response.body = null;\n response.statusCode = 404;\n} else {\n response.statusCode = 204;\n}", "language": "json", "name": "Delete Task After request logic" } ] } [/block] The above code does two things: 1. Return a `404` if nothing matched the `delete` operation. 2. Return a `204` if the `delete` operation matched an existing object in the `Tasks` collection. Your new 'Single call component' form should look like: [block:image] { "images": [ { "image": [ "https://files.readme.io/24EjH6aTAe1WZWhOk3l0_delete-call.png", "delete-call.png", "1180", "1204", "#b67054", "" ] } ] } [/block] Click 'Save'. Now, let's test it! Create a new test named "Delete Task". Choose the `DELETE` method and the `/task/{id}` route. We don't need a body payload for this operation. [block:image] { "images": [ { "image": [ "https://files.readme.io/hYboZ9ngQyc6eaBpNkAA_delete-test.png", "delete-test.png", "1183", "756", "#587697", "" ] } ] } [/block] Click 'Save' and select the newly created test. All you need to do is add an argument with a name of `id` and a value of your previous Task object. We will use `42` again since it exists in our account. Click 'Save' and then click 'Execute'. You should see the following: [block:image] { "images": [ { "image": [ "https://files.readme.io/dMYgVsKYS3CZsiblyblN_deleted.png", "deleted.png", "1160", "1315", "#5c6e73", "" ] } ] } [/block] Go check your `Tasks` collection. You should be missing an object with this `id`. Voilà! You just built a fully functional Tasks API. [block:callout] { "type": "info", "title": "Tasks API", "body": "The fully functional source for this Tasks API is available for download <a target=\"_blank\" href=\"http://downloads.justapis.com/v5.0.0/tasks.json\">here</a>.\n\nYou can import the API into your account and have it immediately ready for use." } [/block]