I took the time yesterday to (start to) take all of my current best practices around API design and put them into one "boilerplate" repo.
This post kicks off a series of blog posts aimed at walking through and explaining this repository in detail.
To let readers know which technologies, libraries, and concepts we'll be going over (and to help with SEO):
We need to install some tools on our system to support the project and tests actually running locally. Then we'll need to install some packages into our project to support the various repetitive tasks of developing code.
We'll be using a couple of tools to execute our development environment, namely <code>git<code>, <code>nodejs<code>, <code>yarn<code> (instead of <code>npm<code>), and <code>docker<code>. I'll leave this up to the reader.
Tip: for <code>nodejs<code> and <code>yarn<code>, use some sort of version manager, like <code>nvm<code> and <code>yvm<code>. It's a good idea for when you're working with different projects with different runtime requirements on your computer. This isn't necessary though, installing from your favorite package manager, or by downloading from their websites, will work just fine.
If you're creating a new project, go ahead and <code>yarn init<code> your way into it. If you're adding the contents of this guide into an existing project, good luck!
Now we're getting into it! Let's install a bunch of packages to aid with development. Run this in your terminal:
Now we've got a <code>node<code> project with some tools installed. Neat.
I like to build projects in a way that use as much "default" configuration options from third party tools as possible. This just keeps things as simple as possible.
Sometimes, though, that's just not possible. Let's create some new config files for some of our tools.
If you've ever worked in a <code>git<code> repository before, this should be of no surprise. Need that <code>.gitignore<code>. I like to use https://gitignore.io for my <code>.gitignore<code> needs. Here's what gitignore.io has for the standard <code>node<code> project: https://gitignore.io/api/node.
There's one more thing to add to our <code>.gitignore<code>, which will be the directory that production builds get transpiled into. We'll be calling that directory <code>dist<code>, so add an entry for <code>dist<code> in your <code>.gitignore<code>, too.
Here's the <code>.gitignore<code> from the final repo: https://github.com/decentorganization/decent-api/blob/master/.gitignore
I've also got and entry for <code>.vscode<code> in there, too, because I like to tell VSCode to auto-format on save, for certain projects, and I don't want those options part of the repo: they're really just my preference.
To manage environment variables on our development machines, we'll use <code>dotenv<code>. This package relies on a file called <code>.env <code> to read environment variables from, and inject them as actual system environment variables into the running <code>node<code> process.
<code>.env<code> is <code>.gitignored<code>, so I like to create a file called <code>.env.example<code> and commit that into the repository. In the README, instruct developers to copy the contents from <code>.env.example<code> into a new (ignored) file named <code>.env<code>.
For our project, the <code>.env(.example)<code> file will hold a port number on which the API should be exposed (<code>API_PORT<code>), database connection information (<code>DB_*<code>) and a "base" logger string (<code>LOGGING_BASE<code>), which can be anything. It's used to prefix logs.
All of the values in this <code>.env.example<code> are defaulted to in the actual codebase. A developer really only needs to create their own <code>.env<code> file if they want to override anything here.
Honestly, I haven't taken much time trying to understand the nuances of <code>babel<code>, so I'll just show you what works for our project. This works for our needs:
<code>nodemon<code> is a simple package that monitors for changes on your filesystem, and kicks of scripts when they do. We'll use <code>nodemon<code> to watch for changes to our source code and test code, then to run the linter and run the tests and restart the development server.
We will ignore the specific directory that holds migration files, because things get weird if those get executed before we're done writing them. (The app executes migrations automatically upon startup, so if we're restarting it in the middle of writing a migration via <code>nodemon<code>, a half-formed migration will be executed against the development database and sucks.)
We're using docker in this project for one very specific purpose: to provide us with a database. We're not dockerizing our project (yet lol).
We'll use <code>docker-compose.yml<code> to specify that we just need a basic <code>postgres<code> service.
Now we'll need to install the packages which will support and enable the actually running API process. Do this in your terminal:
Now we've got all of the tools and packages installed that we'll need to support writing some actual code.
One more thing to do before we can start writing code. We'll add a bunch of scripts to <code>package.json<code> to help us do some common tasks. Add the following <code>scripts<code> object into your <code>package.json<code>:
See the final <code>package.json<code> here: https://github.com/decentorganization/decent-api/blob/master/package.json
And there we have it, our project is finally set up.
Without yet writing a single line of code, we've:
Join me in the next post and we'll start diving into some real code!
Questions? Comments? Ask away over at the Medium post