<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cole Morrison</title>
    <description>The latest articles on DEV Community by Cole Morrison (@jcolemorrison).</description>
    <link>https://dev.to/jcolemorrison</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2741%2F8b7bb91d-4870-41a2-826f-6af024082bb9.png</url>
      <title>DEV Community: Cole Morrison</title>
      <link>https://dev.to/jcolemorrison</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jcolemorrison"/>
    <language>en</language>
    <item>
      <title>Authorized Resources and Database Migrations with Strongloop's Loopback</title>
      <dc:creator>Cole Morrison</dc:creator>
      <pubDate>Fri, 03 Feb 2017 19:13:28 +0000</pubDate>
      <link>https://dev.to/jcolemorrison/authorized-resources-and-database-migrations-with-strongloops-loopback</link>
      <guid>https://dev.to/jcolemorrison/authorized-resources-and-database-migrations-with-strongloops-loopback</guid>
      <description>&lt;p&gt;This post is going to cover the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a Strongloop Loopback and MySQL local environment with Docker&lt;/li&gt;
&lt;li&gt;Hooking up our environment with docker-compose&lt;/li&gt;
&lt;li&gt;Scaffolding out some base models&lt;/li&gt;
&lt;li&gt;Automating Database Migrations and Updates via Loopback&lt;/li&gt;
&lt;li&gt;Protecting REST endpoints with Authorization and Authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main focus will be on Database Migrations / Updates and Authentication/Authorization.  There's a hefty chunk in here regarding creating a standalone MySQL image that won't clobber existing versions on our local machine.  The reason I felt it necessary to include the first few parts is that I personally can't stand it when a guide/tip/tutorial just starts in and assumes everything is already set up.&lt;/p&gt;

&lt;p&gt;If you're just here to learn about Database Migrations, you can skip to that part of the guide.  The scripts to do so are reusable, just swap out your models for the ones within.&lt;/p&gt;

&lt;p&gt;The code for this repository can be found here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jcolemorrison/strongloop-automigration-demo" rel="noopener noreferrer"&gt;https://github.com/jcolemorrison/strongloop-automigration-demo&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Table of Contents
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Preface&lt;/li&gt;
&lt;li&gt;Setting Up The Development Environment&lt;/li&gt;
&lt;li&gt;Setting up a Stand Alone MySQL DB&lt;/li&gt;
&lt;li&gt;Scaffolding Out Our Models&lt;/li&gt;
&lt;li&gt;Automated Database Migrations and Updates&lt;/li&gt;
&lt;li&gt;Final Thoughts&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="preface"&gt;Preface&lt;/h1&gt;

&lt;p&gt;Yes. &lt;a href="https://strongloop.com/" rel="noopener noreferrer"&gt;Strongloop's&lt;/a&gt; &lt;a href="http://loopback.io/" rel="noopener noreferrer"&gt;Loopback&lt;/a&gt;.  That's right.  And yeah, I actually like it.  After doing many many many projects in base ExpressJS, it is massively refreshing to not have to&lt;/p&gt;

&lt;p&gt;a) dig through npm package soup kitchen&lt;br&gt;
b) ID packages that are well maintained&lt;br&gt;
c) connect packages in own home soup&lt;br&gt;
d) maintain / customize packages&lt;br&gt;
e) reinvent the wheel&lt;/p&gt;

&lt;p&gt;Does strongloop loopback solve everything?  I don't know why I even asked that because we all know the answer.  No.  Nothing does.  However, spinning up solid REST APIs, dealing with authentication/authorization, having MULTIPLE datasources (one model to mongo one to sql), routing, docs...&lt;/p&gt;

&lt;p&gt;...all the little things that are no brainers and yet simultaneously timesinks.&lt;/p&gt;

&lt;p&gt;I'd say the only two reasons it's not more ubiquitous is due to two reasons:&lt;/p&gt;

&lt;p&gt;1) Pretty Terrible Documentation&lt;br&gt;
2) Geared Towards Creating APIs, not necessarily with Front Ends&lt;br&gt;
3) Terrible Documentation&lt;/p&gt;

&lt;p&gt;The first one is a usual suspect for most frameworks and is generally the bane of most great dev tools out there.  It's like some teams don't want us to use their stuff.. or they're hiding something..&lt;/p&gt;

&lt;p&gt;The second always seems to be an issue with selection.  Most developers want all in one frameworks to handle front-end, back-end, heroku deploy and free money.  I personally love that it's specialized in APIs and view it as a benefit vs. an issue.  It allows for it to be a much easier player in the service style architecture conversations.&lt;/p&gt;

&lt;p&gt;And third.  Terrible Documentation.  I'm serious, if a developer releases a framework, but no one knows what it does, did a developer release a framework?&lt;/p&gt;

&lt;p&gt;This may raise the question of - "Well, you seem to like it enough."  And I do, because the pain of digging through git issues, learning via experience and peeling through their docs is less than the pain of configuring up a full express application for an API.&lt;/p&gt;

&lt;p&gt;Additionally, once the basic concepts are understood, it's &lt;strong&gt;Very&lt;/strong&gt; productive.&lt;/p&gt;

&lt;p&gt;That was all an aside, but is here for everyone who may or may not lose their minds at the thought of using something other than Express.  Oh by the way, Strongloop is the organization that &lt;em&gt;maintains&lt;/em&gt; Express.  IBM owns Strongloop.  Therefore it's a pretty safe bet that Strongloop Loopback isn't going anywhere.&lt;/p&gt;

&lt;p&gt;Enough of that, let's dig in.&lt;/p&gt;

&lt;h1 id="setting-up"&gt;Setting Up The Development Environment&lt;/h1&gt;

&lt;p&gt;We'll do this real quick with Docker (if you've read any of my other posts, I tend to use it.  A lot.).  Make sure you have it installed and that you also have a &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;https://hub.docker.com/&lt;/a&gt; account and login.  (also make sure to &lt;code&gt;docker login&lt;/code&gt; on the command line with that login).&lt;/p&gt;

&lt;p&gt;Get started with it here: &lt;a href="https://www.docker.com/products/docker" rel="noopener noreferrer"&gt;https://www.docker.com/products/docker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it's perfectly fine to just use a local version of Strongloop and MySQL, I'm segmenting it out in this tutorial so that it's completely separate and won't affect our other installations.&lt;/p&gt;
&lt;h4&gt;
  
  
  1) Create a &lt;code&gt;code&lt;/code&gt; directory and navigate to it in your command line
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;$ mkdir code &amp;amp;&amp;amp; cd code&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Probably didn't need to mention how to do that.&lt;/p&gt;
&lt;h4&gt;
  
  
  2) Create a folder inside of &lt;code&gt;code&lt;/code&gt; called &lt;code&gt;dev-images&lt;/code&gt; and another within that called &lt;code&gt;strongloop&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;$ mkdir -p dev-images/strongloop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We'll house our &lt;code&gt;Dockerfile&lt;/code&gt; that will build out our development Docker image here.&lt;/p&gt;

&lt;p&gt;If you're unfamiliar, this will allow us to run our code within a segmented box (docker container) without having to install any of the dependencies directly.&lt;/p&gt;
&lt;h4&gt;
  
  
  3) Create the Dockerfile inside of &lt;code&gt;code/dev-images/strongloop&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;If we're in &lt;code&gt;code&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ touch dev-images/strongloop/Dockerfile&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;open it in our text editor&lt;/p&gt;
&lt;h4&gt;
  
  
  4) Input the following:
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;From node:6.9.4

# Yarn please
RUN curl -o- -L https://yarnpkg.com/install.sh | bash

ENV PATH="/root/.yarn/bin:${PATH}"

# Installs these globally WITHIN the container, not our local machine
RUN yarn &amp;amp;&amp;amp; yarn global add loopback-cli &amp;amp;&amp;amp; yarn global add nodemon

# Any commands start from this directory IN the container
WORKDIR /usr/src/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This allows us to use Strongloop's CLI, Yarn and Nodemon.  A couple of notes:&lt;/p&gt;

&lt;p&gt;a) Yarn instead of NPM every time (speed, performance, less dupes, yarn.lock for consistency)&lt;/p&gt;

&lt;p&gt;b) Loopback-cli is the "new" cli for Strongloop.  It's what Strongloop would like for everyone to move to vs. &lt;code&gt;strongloop&lt;/code&gt; and &lt;code&gt;slc&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  5) Build the Docker Image
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;code&lt;/code&gt; build the image &lt;code&gt;docker build -t &amp;lt;yourusername&amp;gt;/strongloop-dev dev-images/strongloop/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where &lt;code&gt;&amp;lt;yourusername&amp;gt;&lt;/code&gt; is your username.&lt;/p&gt;

&lt;p&gt;If you've used any of these intermediary images/layers before, you can use the &lt;code&gt;--no-cache=true&lt;/code&gt; to make sure it fresh install and executes.&lt;/p&gt;
&lt;h4&gt;
  
  
  6) Create the &lt;code&gt;docker-compose&lt;/code&gt; file
&lt;/h4&gt;

&lt;p&gt;In the &lt;code&gt;code&lt;/code&gt; directory create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file.  This will be the convenience file for us to up our MySQL database and Strongloop container simultaneously, watch their logs and manage / run commands.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ touch docker-compose.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Inside of the &lt;code&gt;docker-compose.yml&lt;/code&gt; file input the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The standard now&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="c1"&gt;# All of the images/containers compose will deal with&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="c1"&gt;# our strongloop service shall be known as 'api'&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# use your user name&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;yourusername&amp;gt;/strongloop-dev&lt;/span&gt;

    &lt;span class="c1"&gt;# map the containers port of 3000 to our local 3002&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3002:3000&lt;/span&gt;

    &lt;span class="c1"&gt;# mount our current directory (code) to the container's /usr/src/api&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/usr/src/api&lt;/span&gt;

    &lt;span class="c1"&gt;# the default command unless we pass it one&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodemon .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing to note on that's not in the comments is probably our choice to use &lt;code&gt;port&lt;/code&gt; &lt;code&gt;3002&lt;/code&gt; instead of &lt;code&gt;3000&lt;/code&gt;.  &lt;code&gt;3000&lt;/code&gt; is just fine, however whenever I'm developing an API, there's generally another container up somewhere that also wants port &lt;code&gt;3000&lt;/code&gt;.  Obviously we can't map both to the same.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;command&lt;/code&gt; is what will be run, unless we specify otherwise.  The default will be to start the application using Nodemon, so that if we make changes to the files, we don't have to restart the app manually.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;make sure to switch out &lt;code&gt;&amp;lt;yourusername&amp;gt;&lt;/code&gt; with your username&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  7) Scaffold out the Strongloop Application
&lt;/h4&gt;

&lt;p&gt;From our &lt;code&gt;code&lt;/code&gt; directory we can now begin using &lt;code&gt;docker-compose&lt;/code&gt; to manage our commands.  Run the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run api lb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will begin the application scaffolding.  Use the following settings:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What's the name of your application?&lt;/em&gt; Press enter to keep use the current directory&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Which version of LoopBack would you like to use?&lt;/em&gt; Use 3.x&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What kind of application do you have in mind?&lt;/em&gt; api-server&lt;/p&gt;

&lt;p&gt;Now it will scaffold out the application and install dependencies.  It'll use NPM, but we'll yarn-ify that as soon as it's done.&lt;/p&gt;

&lt;h4&gt;
  
  
  8) Once the NPM install is done...
&lt;/h4&gt;

&lt;p&gt;run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run api yarn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will link dependencies, create a yarn.lock file and much more.  This will create consistency in dependencies' dependencies across development environments.  What I mean by that is if someone on another machine &lt;code&gt;yarn&lt;/code&gt;'s this project, they'll definitely get all the correct versions of all the packages every single time.  It won't accidentally upgrade one or anything like that.&lt;/p&gt;

&lt;p&gt;Also, if you're tired of typing &lt;code&gt;docker-compose&lt;/code&gt; 100 times, just open up your &lt;code&gt;.bashrc&lt;/code&gt; and input the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;dco&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docker-compose"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;dcor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docker-compose run"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then in your current terminal session run &lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ source ~/.bashrc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we'd be able to run yarn like so:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ dcor api yarn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;note: you only need to source your current terminal window, any new session from this point on will include those aliases&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  9) Test out your new loopback app
&lt;/h4&gt;

&lt;p&gt;In our &lt;code&gt;code&lt;/code&gt; directory, run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And after it's all setup navigate to &lt;code&gt;localhost:3002/explorer&lt;/code&gt; to see your shiny new api.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;note: even though the container will say it's on &lt;code&gt;localhost:3000&lt;/code&gt;, that's not where it is on our local machine.  Remember, we mapped &lt;code&gt;3000&lt;/code&gt; -&amp;gt; &lt;code&gt;3002&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're interested in learning more about docker, I have an entire guide dedicated to setting up an entire environment on AWS:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://start.jcolemorrison.com/guide-to-fault-tolerant-and-load-balanced-aws-docker-deployment-on-ecs/" rel="noopener noreferrer"&gt;Guide to Fault Tolerant and Load Balanced AWS Docker Deployment on ECS&lt;/a&gt;&lt;/p&gt;

&lt;h1 id="setting-up-mysql"&gt;Setting up a Stand Alone MySQL DB&lt;/h1&gt;

&lt;p&gt;Now we need to setup the MySQL docker image, container and compose service.  Honestly, this is a pretty useful pattern to use in any areas of development where you need a local database.  It will allow you to safely configure a variety of versions of MySQL without fear of clobbering any MySQL setups you may or may not have locally.&lt;/p&gt;

&lt;p&gt;In order to be able to pull down the local &lt;code&gt;mysql&lt;/code&gt; image, as stated at the beginning, you'll need an account for &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;https://hub.docker.com/&lt;/a&gt;.  With that created you'll then need to run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker login&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And use the your hub account credentials.&lt;/p&gt;

&lt;h4&gt;
  
  
  10) Open up our &lt;code&gt;docker-compose.yml&lt;/code&gt; file and modify it to reflect the following:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# The standard now&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2'&lt;/span&gt;

&lt;span class="c1"&gt;# All of the images/containers compose will deal with&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="c1"&gt;# our strongloop service shall be known as 'api'&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# use your user name&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jcolemorrison/strongloop-dev&lt;/span&gt;

    &lt;span class="c1"&gt;# map the containers port of 3000 to our local 3002&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3002:3000&lt;/span&gt;

    &lt;span class="c1"&gt;# mount our current directory (code) to the container's /usr/src/api&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/usr/src/api&lt;/span&gt;

    &lt;span class="c1"&gt;# the default command unless we pass it one&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodemon .&lt;/span&gt;

  &lt;span class="c1"&gt;# ADD HERE.  This is what our MySQL service shall be known as&lt;/span&gt;
  &lt;span class="na"&gt;mysqlDb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="c1"&gt;# This is the official MySQL 5.6 docker image&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:5.6&lt;/span&gt;

    &lt;span class="c1"&gt;# These are required variables for the official MySQL image&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${DB_ROOT}"&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${DB_NAME}"&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${DB_USER}"&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${DB_PWD}"&lt;/span&gt;

    &lt;span class="c1"&gt;# Keep it mapped to the usual MySQL port&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;3306:3306&lt;/span&gt;

    &lt;span class="c1"&gt;# Create a separate volume on our machine to map to the container's default mysql data directory&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;strongloopDev:/var/lib/mysql&lt;/span&gt;

&lt;span class="c1"&gt;# These must be declared to be used above&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;strongloopDev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's 3 major differences here from the previous service (&lt;code&gt;api&lt;/code&gt;) that we defined:&lt;/p&gt;

&lt;p&gt;a) We're using an &lt;code&gt;environment&lt;/code&gt; field.  It's declaring values that are required by the MySQL image if we want the database to go up and work without a ton of extra work.  You can read more about the official MySQL image &lt;a href="https://hub.docker.com/_/mysql/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MYSQL_ROOT_PASSWORD: Password to our `root` user
MYSQL_DATABASE: Our DB name
MYSQL_USER: Our `user` that's not `root`
MYSQL_PASSWORD: Our `user` password
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where do we get the interpolated values though in the actual file?  docker-compose will look for a &lt;code&gt;.env&lt;/code&gt; file in the same directory and make those values available inside of the file.  We'll make that next.&lt;/p&gt;

&lt;p&gt;b) We're creating and mapping a volume called &lt;code&gt;strongloopDev&lt;/code&gt; to our container's mysql data directory.  This is exactly like what we did above with mounting our current directory to the container's.  However, instead of the current directory, Docker has an area on our machine that it will create a directory and mount for us.  That's more of an explanation for understanding that direct accuracy of what's happening.&lt;/p&gt;

&lt;p&gt;Just think, when we define a volume like so, docker creates a folder (&lt;code&gt;strongloopDev&lt;/code&gt;) on our machine where it's files our located.  It mounts that to the path we hand it, which in our case was &lt;code&gt;/var/lib/mysql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before we make our &lt;code&gt;.env&lt;/code&gt; file, why MySQL 5.6?  This is simple, because in production, I use &lt;a href="https://aws.amazon.com/rds/aurora/" rel="noopener noreferrer"&gt;Amazon Aurora DB&lt;/a&gt;, which is drop-in compatible with 5.6.&lt;/p&gt;

&lt;h4&gt;
  
  
  11) In the &lt;code&gt;code&lt;/code&gt; directory create a new file &lt;code&gt;.env&lt;/code&gt; and input the following:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DB_NAME=strongdevdb
DB_USER=strongdevuser
DB_PWD=strongdevpwd
DB_ROOT=strongroot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, now those values in our &lt;code&gt;docker-compose&lt;/code&gt; file will fill in correctly.&lt;/p&gt;

&lt;h4&gt;
  
  
  12) In our &lt;code&gt;code&lt;/code&gt; directory, run the following to up the api server and mysql service:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;we can also run &lt;code&gt;docker-compose up -d&lt;/code&gt; to have the service start in the back ground and then &lt;code&gt;docker-compose logs -f&lt;/code&gt; to view the logs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's confirm that our MySQL db is indeed alive.  Run the following in another tab (in the same &lt;code&gt;code&lt;/code&gt; directory of course):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run mysqlDb mysql -h &amp;lt;yourlocalip&amp;gt; -P 3306 -u strongdevuser -p&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Where &lt;code&gt;&amp;lt;yourlocalip&amp;gt;&lt;/code&gt; is the IPv4 address (i.e. 10.0.0.100) in your local network.  To find it run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ifconfig | grep 'inet '&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and it should be the second of the two addresses.&lt;/p&gt;

&lt;p&gt;After running the mysql command, we'll be prompted for the password to our &lt;code&gt;strongdevuser&lt;/code&gt;, which is &lt;code&gt;strongdevpwd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once inside run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;show databases;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we'll see our DB has been created.  Then run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;use strongdevdb;&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  13) Install the &lt;code&gt;loopback-connector-mysql&lt;/code&gt; package
&lt;/h4&gt;

&lt;p&gt;In our &lt;code&gt;code&lt;/code&gt; run the following (either in yet another new tab, or you can stop our service, or the mysql db tab and run it there):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run api yarn add loopback-connector-mysql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This package allows us to hook up our loopback application to MySQL.&lt;/p&gt;

&lt;p&gt;Once it's completed installing, in our text editor, open up &lt;code&gt;server/datasources.json&lt;/code&gt;.  Modify it to reflect the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"memory"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"connector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"database"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strongdevdb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strongdevpwd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strongdevuser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3306&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysqlDb"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All the top level key of &lt;code&gt;mysql&lt;/code&gt; is, is just a reference for loopback (as is it's name property).  All but the &lt;code&gt;host&lt;/code&gt; property should be pretty explanatory.  Generally, if this were a local db, we'd input something like &lt;code&gt;localhost&lt;/code&gt; or a specific IP.  But since these are docker containers, we get to reference them as their service name!  When &lt;code&gt;docker-compose&lt;/code&gt; ups our containers together, it makes each service's name available to each other as a host as its name.&lt;/p&gt;

&lt;p&gt;Excellent, now our MySQL and Loopback service are ready to work together.&lt;/p&gt;

&lt;h1 id="scaffolding-out-models"&gt;Scaffolding Out Our Models&lt;/h1&gt;

&lt;p&gt;Now we're going to create two models.  One will be our own type of user called &lt;code&gt;Client&lt;/code&gt; and the other will be a luxurious, exotic type called &lt;code&gt;Widget&lt;/code&gt;.  We'll be using these to demonstrate DB Migration, Authentication and Authorization.&lt;/p&gt;

&lt;p&gt;Let's begin the &lt;code&gt;client&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  14) In the &lt;code&gt;code&lt;/code&gt; directory, run the following:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run api lb model Client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;(seriously, if you work with docker a lot, use those aliases I mentioned)&lt;/p&gt;

&lt;p&gt;This will begin the model scaffolder.  Use the following settings:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enter the model name:&lt;/em&gt; press enter here to use &lt;code&gt;Client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Select the data-source to attach Client to:&lt;/em&gt; Use &lt;code&gt;mysql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Select model's base class&lt;/em&gt;: Scroll down and select &lt;code&gt;User&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Expose Client via the REST API?&lt;/em&gt; press &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;enter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Custom plural form (used to build REST URL)&lt;/em&gt; just press enter, it will default to &lt;code&gt;clients&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Common model or server only?&lt;/em&gt; use &lt;code&gt;server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After that, press enter again on properties.  We don't want to add any extras.  We'll get all of the properties that the built in loopback user gets.&lt;/p&gt;

&lt;p&gt;So real quick aside.  Why are we making a brand new User?  Because in Strongloop's infinite wisdom they decided two things:&lt;/p&gt;

&lt;p&gt;a) The built in user shall be called &lt;code&gt;User&lt;/code&gt;&lt;br&gt;
b) The only way to extend its functionality, is to extend it with your own model&lt;/p&gt;

&lt;p&gt;This is probably one of the most annoying things and yet so small.  They could've easily called it &lt;code&gt;BaseUser&lt;/code&gt; so that we could call ours &lt;code&gt;User&lt;/code&gt;.  Support the change here: &lt;a href="https://github.com/strongloop/loopback/issues/3028" rel="noopener noreferrer"&gt;https://github.com/strongloop/loopback/issues/3028&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  15) Create the &lt;code&gt;Widget&lt;/code&gt; model by running the following:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run api lb model Widget&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Just like before, we'll walk through this process and create some settings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enter the model name:&lt;/em&gt; press enter here to use &lt;code&gt;Widget&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Select the data-source to attach Client to:&lt;/em&gt; Use &lt;code&gt;mysql&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Select model's base class&lt;/em&gt;: Scroll down and select &lt;code&gt;Persisted Model&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Expose Client via the REST API?&lt;/em&gt; press &lt;code&gt;y&lt;/code&gt; and &lt;code&gt;enter&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Custom plural form (used to build REST URL)&lt;/em&gt; just press enter, it will default to &lt;code&gt;widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Common model or server only?&lt;/em&gt; use &lt;code&gt;server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For Properties, for the first one:&lt;/p&gt;

&lt;p&gt;Property Name: &lt;code&gt;name&lt;/code&gt;&lt;br&gt;
Property Type: &lt;code&gt;string&lt;/code&gt;&lt;br&gt;
Required: &lt;code&gt;n&lt;/code&gt;&lt;br&gt;
Default Value: leave blank for none&lt;/p&gt;

&lt;p&gt;For the second:&lt;/p&gt;

&lt;p&gt;Property Name: &lt;code&gt;description&lt;/code&gt;&lt;br&gt;
Property Type: &lt;code&gt;string&lt;/code&gt;&lt;br&gt;
Required: &lt;code&gt;n&lt;/code&gt;&lt;br&gt;
Default Value: leave blank for none&lt;/p&gt;

&lt;p&gt;After those two, just press enter again on the third property with nothing entered and it will exit you out.&lt;/p&gt;
&lt;h4&gt;
  
  
  16) Relate the &lt;code&gt;Widget&lt;/code&gt; and &lt;code&gt;Client&lt;/code&gt; via a &lt;code&gt;hasMany&lt;/code&gt; relation:
&lt;/h4&gt;

&lt;p&gt;This is an awesome, and very Rail-sy feature.  We can easily associated models and automatically have the associated rest endpoints created.  In our case here we're going to make it so that a &lt;code&gt;Client&lt;/code&gt; &lt;code&gt;hasMany&lt;/code&gt; &lt;code&gt;Widget&lt;/code&gt;s via the endpoint:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/clients/:id/widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Which again, while pretty "straightforward" would be a file scaffolding timesink in raw ExpressJs.  Let's do this by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker-compose run api lb relation&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Use the following settings:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Select the model to create the relationship from:&lt;/em&gt; select &lt;code&gt;Client&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Relation type:&lt;/em&gt; select &lt;code&gt;hasMany&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Choose a model to create a relationship with&lt;/em&gt; select &lt;code&gt;Widget&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Enter the property name for the relation:&lt;/em&gt; press enter to accept &lt;code&gt;widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Optionally enter a custom foreign key:&lt;/em&gt; press enter and it will by default use &lt;code&gt;widgetId&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Require a through model?&lt;/em&gt; type &lt;code&gt;n&lt;/code&gt; and press enter&lt;/p&gt;

&lt;p&gt;and our relation is created.&lt;/p&gt;

&lt;p&gt;We can view this in our code by navigating to &lt;code&gt;server/models/client.json&lt;/code&gt; and we'll see the relation and all of our properties have been scaffolded out.&lt;/p&gt;

&lt;p&gt;That's also the really neat thing with loopback.  We define our models by simply creating a json file.  All the scaffolding tool did was create this and the accompanying &lt;code&gt;.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;It also adds the new models to our &lt;code&gt;server/model-config.json&lt;/code&gt; file which is basically the master config file for all loopback models.  Go ahead and open that now.  You're should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/common/models"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/server/models"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"../common/models"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"./models"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mixins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/common/mixins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/server/mixins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"../common/mixins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"./mixins"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AccessToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ACL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"RoleMapping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Client"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Widget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Immediately, we should notice a problem.  Everything except our &lt;code&gt;Client&lt;/code&gt; and &lt;code&gt;Widget&lt;/code&gt; models use the &lt;code&gt;db&lt;/code&gt; in memory store.  Change all of those &lt;code&gt;mysql&lt;/code&gt; and also set the &lt;code&gt;User&lt;/code&gt; to have a property of &lt;code&gt;public: false&lt;/code&gt; since we have to use our extended &lt;code&gt;Client&lt;/code&gt; model.  The &lt;code&gt;model-config.json&lt;/code&gt; file should now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sources"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/common/models"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/server/models"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"../common/models"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"./models"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mixins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/common/mixins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"loopback/server/mixins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"../common/mixins"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"./mixins"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"AccessToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ACL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"RoleMapping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Client"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Widget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dataSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mysql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Excellent&lt;/p&gt;

&lt;h4&gt;
  
  
  17) Head back over to &lt;code&gt;localhost:3002/explorer&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;a) Click on the &lt;code&gt;Widget&lt;/code&gt; option to see a list of endpoints that have been created.&lt;/p&gt;

&lt;p&gt;b) Click on the &lt;code&gt;GET /Widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we'll see that it's failed.  Even though we've setup our application logic to deal with models and relations, we have not informed our DB of the change.  Let's do that now.&lt;/p&gt;

&lt;p&gt;Just as a note, we're doing this via the UI console instead of &lt;code&gt;curl&lt;/code&gt; simply for less steps and brevity.  We can create requests to the API by simply doing somthing akin to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;user@name.com&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;localhost:3002/api/clients/login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above would grab your access token, and then to grab the widgets authenticated we'd do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: TOKEN_WE_JUST_GOT"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     localhost:3002/api/widgets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Really, the important part there is how to set the AUTH header.  Other than that it's straightforward.&lt;/p&gt;

&lt;h1 id="database-migration"&gt;Automated Database Migrations and Updates&lt;/h1&gt;

&lt;p&gt;A recurring problem in any type of application that develops around ANY type of database is changing schemas, tables and data structures.  Most application stacks, specifically Rails, have a great way to handle this (well or at least a way).  In the world of Node however, good luck.  Sequelize has some, but as is classic dev teams - the documentation is bad.  Knex and Bookshelf are pretty awesome, but that requires config'ing express of course.  Sails.js and friends have Waterline, but last I looked in to Sails.js, they had split and now I have no idea if it's Sails, Trails or whatever.&lt;/p&gt;

&lt;p&gt;And lets not get started on Mongo.  The number of developers that just pick mongo because it looks like JSON is hilarious.  And inevitably, as is the case with MOST data in MOST apps, they require relations.  And as soon as all the data starts getting super relational heavy, all the benefits of NoSQL start disappearing (quickly).&lt;/p&gt;

&lt;p&gt;Back on topic here.  Strongloop's Loopback actually has a pretty great migration/update system.  However, you'd think they'd want you to not know about it.  It's not that it's not documented, it's just worded very oddly.  There's two functions:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;automigrate&lt;/code&gt; - updates your tables but drops all the data in existing ones.  Ouch.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;autoupdate&lt;/code&gt; - updates tables.&lt;/p&gt;

&lt;p&gt;When first reading it, and maybe it's just me, I assumed that &lt;code&gt;autoupdate&lt;/code&gt; was only something one could perform if the table was already in existence.  So of course that lead to this weird conundrum of looking for a way to create the table if it does not exist and update it if it does and only if it needs to be updated.&lt;/p&gt;

&lt;p&gt;THANKFULLY, despite it being terribly documented, we can achieve this.&lt;/p&gt;

&lt;p&gt;What we're going to do is two fold:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a)&lt;/strong&gt; Create a migration script that will create our tables and drop current ones.  We can run this when we need to refresh our local dev environment or add seed data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;b)&lt;/strong&gt; Create a set of auto update scripts that will keep our database in sync with all of our &lt;code&gt;models/model.json&lt;/code&gt; files!&lt;/p&gt;

&lt;h4&gt;
  
  
  18) Create a new folder &lt;code&gt;bin&lt;/code&gt; in our &lt;code&gt;code&lt;/code&gt; directory.  Create a file inside of &lt;code&gt;bin&lt;/code&gt; called &lt;code&gt;migrate.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;So the full file path to this in our &lt;code&gt;code&lt;/code&gt; directory is &lt;code&gt;bin/migrate.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Inside put the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// import our app for one time usage&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../server/server.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// reference to our datasource that we named 'mysql'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataSources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mysql&lt;/span&gt;

&lt;span class="c1"&gt;// the basic loopback model tables&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AccessToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ACL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RoleMapping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// our custom models&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;custom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Widget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lbTables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Run through and create all of them&lt;/span&gt;
&lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;automigrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lbTables&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tables [&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;lbTables&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;] reset in &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;optional aside&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I hate semicolons and long lines, so if your editor is complaining just modify your &lt;code&gt;.eslintrc&lt;/code&gt; file in your &lt;code&gt;code&lt;/code&gt; directory to reflect the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"loopback"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parserOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ecmaVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"semi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"never"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"space-before-function-paren"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"always"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"max-len"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;/end optional aside&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  19) Run the migration script
&lt;/h4&gt;

&lt;p&gt;In our &lt;code&gt;code&lt;/code&gt; directory run the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose run api node bin/migrate.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once done, hop over into your mysql DB command line and run&lt;/p&gt;

&lt;p&gt;&lt;code&gt;show tables;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And we'll see that all of our tables now exist.&lt;/p&gt;

&lt;h4&gt;
  
  
  20) Create a &lt;code&gt;Widget&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Hop back over to our &lt;code&gt;localhost:3002&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;a) Find &lt;code&gt;POST /Widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;b) Create &lt;code&gt;{"name": "amazing widget", "description": "so good"}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fwww.jcolemorrison.com%2Fblog%2Fposts%2Fstrongloop-loopback-docker-1-29-2017%2Fstep-20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fwww.jcolemorrison.com%2Fblog%2Fposts%2Fstrongloop-loopback-docker-1-29-2017%2Fstep-20.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c) Click &lt;code&gt;Try it out!&lt;/code&gt; and the &lt;code&gt;Widget&lt;/code&gt; will be created.&lt;/p&gt;

&lt;p&gt;Now to solve updating tables with new schemas.&lt;/p&gt;

&lt;h4&gt;
  
  
  21) Navigate to &lt;code&gt;server/models/widget.json&lt;/code&gt; and add the following property:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;size&lt;/code&gt; is our new property.&lt;/p&gt;

&lt;h4&gt;
  
  
  22) Head back to &lt;code&gt;localhost:3002/explorer&lt;/code&gt; and attempt the following &lt;code&gt;Widget&lt;/code&gt;:
&lt;/h4&gt;

&lt;p&gt;a) Find &lt;code&gt;POST /Widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;b) Create &lt;code&gt;{"name": "huge widget", "description": "huge", "size": 10}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;c) Click &lt;code&gt;Try it out!&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And it will fail with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Unknown column 'size' in 'field list'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's create those &lt;code&gt;Autoupdate&lt;/code&gt; scripts now&lt;/p&gt;

&lt;h4&gt;
  
  
  23) Create a new file at &lt;code&gt;server/boot/base.migration.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Inside of this file, we'll create the auto updating of Loopback's built in models.  Input the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// the base loopback models&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;AccessToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ACL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RoleMapping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateBaseModels&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// reference to our datasource&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataSources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mysql&lt;/span&gt;

  &lt;span class="c1"&gt;// check to see if the model is out of sync with DB&lt;/span&gt;
  &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isActual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;syncStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actual&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;out of sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Base models are &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;syncStatus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// if the models are in sync, move along&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Migrating Base Models...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// update the models&lt;/span&gt;
    &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;autoupdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Base models migration successful!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving this file, if we head back over to our logs, we'll see the message that they're in sync.  We haven't changed them, and honestly probably won't even change the base models, but just in case we ever need to finagle them.&lt;/p&gt;

&lt;h4&gt;
  
  
  24) Create a new file at &lt;code&gt;server/boot/custom.migration.js&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Finally, for our custom models, even though these script are basically identical, it's convenience since we might have to change they way they update in the future that differs from the base ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Widget&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateCustomModels&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mysql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataSources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mysql&lt;/span&gt;
  &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isActual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;syncStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actual&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;out of sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Custom models are &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;syncStatus&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Migrating Custom Models...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nx"&gt;mysql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;autoupdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Custom models migration successful!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No comments for this one since it's the same.&lt;/p&gt;

&lt;p&gt;One aside though is &lt;code&gt;boot&lt;/code&gt;.  This directory, as its name suggests, inclues scripts that are run everytime the loopback app is booted up.  So in this case, when our app is restarted, it will always seek to ensure that our models are in sync with our database based on our &lt;code&gt;model.json&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;After saving this, back in the console we should see the message that our custom models have been migrated successfully!  Let's go back over and create that huge widget now.&lt;/p&gt;

&lt;h4&gt;
  
  
  25) Head back to &lt;code&gt;localhost:3002/explorer&lt;/code&gt; and create the huge widget
&lt;/h4&gt;

&lt;p&gt;a) Find &lt;code&gt;POST /Widgets&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;b) Create &lt;code&gt;{"name": "huge widget", "description": "huge", "size": 10}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;c) Click &lt;code&gt;Try it out!&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And everything should work as planned.  From now on if we update a model's json file and reboot, the MySQL DB will automatically update.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fwww.jcolemorrison.com%2Fblog%2Fposts%2Fstrongloop-loopback-docker-1-29-2017%2Fstep-25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fwww.jcolemorrison.com%2Fblog%2Fposts%2Fstrongloop-loopback-docker-1-29-2017%2Fstep-25.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you'd like to verify these are indeed in existence, just head back over to the Mysql DB and do a &lt;code&gt;select * from Widget;&lt;/code&gt; and you'll see our beautiful widgets.  Of course it's missing &lt;code&gt;clientID&lt;/code&gt; because haven't created any through a relation yet, which we'll do next.&lt;/p&gt;

&lt;h1 id="auth-resources"&gt;Authenticating and Authorizing Resources&lt;/h1&gt;

&lt;p&gt;Strongloop has a very brilliant (and fun) and yet terribly documented and confusing concept for authorization.  It's known as ACLs or 'access control lists'.  They have a bit of a learning curve, but once over that are incredibly useful. Not to mention better than most of the other package soup authorization libraries out there.&lt;/p&gt;

&lt;p&gt;In a &lt;code&gt;model.json&lt;/code&gt; file there is a property called &lt;code&gt;acls&lt;/code&gt;.  It's an array and accepts a set of objects that follow the pattern of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;EXECUTE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;APP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ROLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`Role`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;few&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;we'll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;mention&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;below&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ALLOW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DENY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"property"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;methods&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;single&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;applies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;too&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most common setup we'll use is a &lt;code&gt;principalType: ROLE&lt;/code&gt; which then allows us to use a &lt;code&gt;principleId&lt;/code&gt; of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$owner&lt;/code&gt; - only the resource owner may access&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$everyone&lt;/code&gt; - anyone may access&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$authenticated&lt;/code&gt; - only logged in users may access&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$unauthenticated&lt;/code&gt; - logged out users&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;custom&lt;/code&gt; - we can define our own roles!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These ACLs have an order of precedence in which they apply.  In simple terms, that means if you apply 3 different ACLs, there is a set order by which loopback will determine the final permission.  This is actually made pretty clear at the end of their docs&lt;/p&gt;

&lt;p&gt;&lt;a href="http://loopback.io/doc/en/lb3/Controlling-data-access.html#acl-rule-precedence" rel="noopener noreferrer"&gt;http://loopback.io/doc/en/lb3/Controlling-data-access.html#acl-rule-precedence&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The way I like to think about it is using a visual.&lt;/p&gt;

&lt;p&gt;I have a resource.  In our case a Widget.  And it's huge and green.&lt;/p&gt;

&lt;p&gt;There's a road to it that's letting everyone in.&lt;/p&gt;

&lt;p&gt;In order to filter out only the traffic I want, I'll put security guard posts along the road to the Widget.&lt;/p&gt;

&lt;p&gt;The guard posts in this case are ACLs.  They each have their own set of rules to let traffic in.&lt;/p&gt;

&lt;p&gt;Anyhow..&lt;/p&gt;

&lt;p&gt;Before anything, let's create our first related widget.&lt;/p&gt;

&lt;h4&gt;
  
  
  26) Head over to the &lt;code&gt;localhost:3002/explorer&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;a) Under &lt;code&gt;Client&lt;/code&gt; find &lt;code&gt;POST /Clients&lt;/code&gt; and let's create a user and use the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"email": "test@widget.com", "password": "test"}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;b) After our user has been created find &lt;code&gt;POST /Clients/login&lt;/code&gt; and use the following (the same as what you signed up with):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"email": "test@widget.com", "password": "test"}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After this is posted it will return an instance of an &lt;code&gt;Access Token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fwww.jcolemorrison.com%2Fblog%2Fposts%2Fstrongloop-loopback-docker-1-29-2017%2Fstep-26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3-us-west-1.amazonaws.com%2Fwww.jcolemorrison.com%2Fblog%2Fposts%2Fstrongloop-loopback-docker-1-29-2017%2Fstep-26.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From this, grab the &lt;code&gt;id&lt;/code&gt; property of the returned token, paste it into the &lt;code&gt;Set Access Token&lt;/code&gt; field in the navigation bar and set it.&lt;/p&gt;

&lt;p&gt;All this does is add our access token to each request from this point on.&lt;/p&gt;

&lt;p&gt;Also note our &lt;code&gt;userId&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;c) Find &lt;code&gt;POST /Clients/:id/widgets&lt;/code&gt;, enter your &lt;code&gt;userId&lt;/code&gt; for &lt;code&gt;id&lt;/code&gt; and post the following widget:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"name": "user widget", "description": "user awesome", "size": 5}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We'll receive an Authorization error here.  That's because, by default, related resources are not allowed to be executed/read from by their related model.&lt;/p&gt;

&lt;h4&gt;
  
  
  27) Hop over to &lt;code&gt;client.json&lt;/code&gt; and add the following object in the &lt;code&gt;acls&lt;/code&gt; array:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EXECUTE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$authenticated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"property"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"__create__widgets"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above ACL says, allow a &lt;code&gt;Client&lt;/code&gt; to create a &lt;code&gt;Widget&lt;/code&gt; via the related method &lt;code&gt;__create__widgets&lt;/code&gt; IF the &lt;code&gt;Client&lt;/code&gt; is authenticated.&lt;/p&gt;

&lt;p&gt;All related model methods follow the pattern of &lt;code&gt;__action__relatedModelPluralName&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However, just because we can &lt;code&gt;POST&lt;/code&gt; them does not mean we can fetch them.  Add one more ACL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"READ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$owner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"property"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"__get__widgets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"__findById__widgets"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above states that if our &lt;code&gt;Client&lt;/code&gt; is the owner, meaning their &lt;code&gt;clientId&lt;/code&gt; is present as a foreign key on the widget, allow them to fetch the widget via either a full get list or as an individual find by id.&lt;/p&gt;

&lt;p&gt;For a list of &lt;em&gt;some&lt;/em&gt; of the related model methods - see this doc: &lt;a href="http://loopback.io/doc/en/lb3/Accessing-related-models.html" rel="noopener noreferrer"&gt;http://loopback.io/doc/en/lb3/Accessing-related-models.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I say some, because I keep finding methods and aliases that aren't documented anywhere.&lt;/p&gt;

&lt;p&gt;The final &lt;code&gt;client.json&lt;/code&gt; should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Client"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"base"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"User"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"idInjection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"validateUpsert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"validations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"relations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"widgets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hasMany"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Widget"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"foreignKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"acls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EXECUTE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$authenticated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"property"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"__create__widgets"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"READ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$owner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALLOW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"property"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"__get__widgets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"__findById__widgets"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"methods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  28) Head back to &lt;code&gt;localhost:3002/explorer&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; the widget
&lt;/h4&gt;

&lt;p&gt;Find &lt;code&gt;POST /Clients/:id/widgets&lt;/code&gt;, enter your &lt;code&gt;userId&lt;/code&gt; for &lt;code&gt;id&lt;/code&gt; and post the following widget:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{"name": "user widget", "description": "user awesome", "size": 5}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now it will work.  Fabulous.  One more problem though.  We can still &lt;code&gt;POST&lt;/code&gt; directly to the &lt;code&gt;Widgets&lt;/code&gt; API.  That means Widgets can be created without owners, which may be what we want or it may not be.  In order to lock down the &lt;code&gt;Widget&lt;/code&gt; api...&lt;/p&gt;

&lt;h4&gt;
  
  
  29) Open up &lt;code&gt;server/widget.json&lt;/code&gt; and add the following ACL:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$everyone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DENY"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This just straight up denies anyone from accessing widgets directly.  The access via the client will still work though.  When no &lt;code&gt;property&lt;/code&gt; is supplied, it assumes ALL.  The final &lt;code&gt;widget.json&lt;/code&gt; should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Widget"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"base"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PersistedModel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"idInjection"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"validateUpsert"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"validations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"relations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"acls"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"accessType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"principalType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$everyone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DENY"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"methods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The alternative to this would just be to go to our &lt;code&gt;model-config.json&lt;/code&gt; and change the &lt;code&gt;public: true&lt;/code&gt; to &lt;code&gt;public: false&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id="final-thoughts"&gt;Final Thoughts&lt;/h1&gt;

&lt;p&gt;As with most things within the Node community, Strongloop Loopback has a ton of major advantages and powerful features... however it's documentation is incredibly lacking.  I'm still a huge proponent of it though simply because of how productive one can be in such a short amount of time.  So many REST APIs have SO many things in common, why do them all again?&lt;/p&gt;

&lt;p&gt;Setting up custom REST methods, roles and hooking up to Passport oAuth is pretty straight forward. Not to mention integrating with almost any Express package is simple since it's just an extension of Express.  And with a nice and simple migration system, it takes a lot of headache out of the process.&lt;/p&gt;

&lt;p&gt;I've got a video series in the works that should be out in the next couple of months that will include a super deep dive into Strongloop's Loopback, using it with Docker and deploying it to hook up with a separate react webservice all inside of AWS!&lt;/p&gt;

&lt;p&gt;If the video series sounds like something of interest, or if you'd like to subscribe and get all of my weekly guides in your inbox, signup for my mailing list!&lt;/p&gt;




&lt;p&gt;As always, please leave me a comment or drop a line if there's any technical glitches or problems.&lt;br&gt;
&lt;/p&gt;


&lt;p&gt;This was originally posted on &lt;a href="http://start.jcolemorrison.com/authorized-resources-and-database-migrations-with-strongloops-loopback/" rel="noopener noreferrer"&gt;J Cole Morrison: Tech Guides and Thoughts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out some of my other guides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://start.jcolemorrison.com/guide-to-fault-tolerant-and-load-balanced-aws-docker-deployment-on-ecs/" rel="noopener noreferrer"&gt;Guide to Fault Tolerant and Load Balanced AWS Docker Deployment on ECS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://start.jcolemorrison.com/no-eject-create-react-app-with-sass-storybook-and-yarn-in-a-docker-environment/" rel="noopener noreferrer"&gt;Create React App with SASS, Storybook and Yarn in a Docker Environment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;





</description>
      <category>strongloop</category>
      <category>loopback</category>
      <category>node</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
