From a49a53903dff06678faed80c390ceae4ae60dee7 Mon Sep 17 00:00:00 2001 From: David Erwin Date: Fri, 23 Jun 2017 13:29:35 -0400 Subject: [PATCH] Finish quickstart first draft --- docs/plugins-quickstart.md | 122 ++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/docs/plugins-quickstart.md b/docs/plugins-quickstart.md index 38303bd5c..12d30c515 100644 --- a/docs/plugins-quickstart.md +++ b/docs/plugins-quickstart.md @@ -95,7 +95,7 @@ cd /path/to/talk/plugins ln -s /path/to/your/plugin ``` -or in this case: +or in this case, from the directory create above: ``` cd ../talk/plugins @@ -112,3 +112,123 @@ All plugins contain server and/or client index files, which export all plugin fu // talk-plugin-asset-manager/index.js module.exports = {}; ``` + +## Build the feature! + +Now that the plugin is set up I can get down to writing the feature. My goal is to allow my CMS to push new assets as they are created into Talk. To accomplish this, I will create a POST endpoint using Talk's [route api](plugins-server.html#field-router). + +### Create a route + +When designing my api, I want to be careful to avoid conflicts with not only the existing Talk api, but other plugins in the open source ecosystem that may be creating routes. To do this, I'll follow the golden rule of creating universals with plugins: + +_Always namespace all universals with your plugin's unique name._ + +To ensure everything is hooked up, I'll log the request body (POST payload in this case) to the console and echo it as the response: + +``` +// talk-plugin-asset-manager/index.js +module.exports = { + router(router) { + router.post('/api/v1/asset-manager', (req, res) => { + console.log(req.body); + res.json(req.body); + }); + } +} +``` + +When I save this file, I reflexively check my console to be sure that the server restarts. + +To test that this works, I can: + +``` +$ curl -H "Content-Type: application/json" -X POST -d '{"url":"http://localhost:3000/my-article.html","title":"My Article"}' http://localhost:3000/api/v1/asset-manager +{"url":"http://localhost:3000/my-article.html","title":"My Article"} +``` + +After hitting the endpoint, I can also look at the terminal running `yarn dev-start` and see the access log and my `console.log()` statement: + +``` +{ url: 'http://localhost:3000/my-article.html', + title: 'My Article' } +POST /api/v1/asset-manager 200 1.379 ms - 682309 +``` + +### Save the asset + +When I save this asset, I will use Talk's [asset model](https://github.com/coralproject/talk/blob/master/models/asset.js). + +Mongo has a handy method [findOneAndUpdate](https://docs.mongodb.com/v3.2/reference/method/db.collection.findOneAndUpdate/) that will take care determining whether or not this asset exists, then either updating or inserting it. Whenever possible, we recommend using these atomic patterns that prevent multiple queries to the db and the efficiency problems and race conditions that they cause. + +``` +// talk-plugin-asset-manager/index.js + +const AssetModel = require('models/asset'); + +module.exports = { + router(router) { + router.post('/api/v1/asset-manager', (req, res) => { + + const asset = req.body; + const update = {$setOnInsert: {url: asset.url}}; + + AssetModel.findOneAndUpdate(asset, update, { + new: true, + upsert: true, + setDefaultsOnInsert: true + }) + .then((asset) => res.json(asset)); + }); + } +} +``` + +I can now run the `curl` command as before, then see my new asset in my db! + +We have an alpha version of our plugin! + +### More work to be done + +The purpose of this tutorial is to follow the full lifecycle of a plugin, from conception through publication into deployment. With that in mind we'll move forward with this alpha version. + +Some things to make this production ready: + +* refactoring to separate concerns, +* commenting, +* adding tests, +* validating data, +* [adding security](https://github.com/coralproject/talk/blob/b805451d376d2892c81c58d8822a85563e469b88/routes/api/users/index.js#L14) +* incorporating [domain whitelisting](https://github.com/coralproject/talk/blob/b805451d376d2892c81c58d8822a85563e469b88/services/assets.js#L60). + +It is important to realize that when you're writing a Talk plugin you are writing a program that may be touched by other devs and could grow in size and complexity. Bring your best engineering sensibilities to bear. + +## Publishing the plugin + + +### Publish to npm + +In order to [register](http://localhost:4000/plugins.html#plugin-registration) your _published_ plugin, you will need to [publish it to npm](https://docs.npmjs.com/getting-started/publishing-npm-packages). + +Once the package is published, update `plugins.json` to use the published plugin: + +``` +{ + "server": [ + ... + {"talk-plugin-asset-manager": "^0.1"} + ], + ... +} +``` + +Finally, run the `reconcile` script to install the plugin from npm. + +``` +$ bin/cli plugins reconcile +``` + +### Publish to version control + +This plugin is open source, so I'm also going to [publish it to github](https://github.com/jde/talk-plugin-asset-manager/commit/66b626caa85cb8030b3ddaa7c1a4821bf01e350a) and [cut a release](https://github.com/jde/talk-plugin-asset-manager/releases/tag/v0.1) that mirrors the npm relese. + +## Done!