One of the best aspects of LoopBack is how quickly you can get up to speed and start building your own API. But as we all know, “With great power comes great responsibility.” While you can bang out an API in minutes, it may benefit you to slow down a bit and think about a few best practices

“A rose by any other name”, or how to name stuff

One of the very first decisions you have to make when creating an API is what to name the model. Here are some tips/suggestions:

  • Use the singular name for your model. LoopBack will automatically create a plural form (and let you customize it you want), but the expectation is that your model name will be singular. So, for example, you should use “cat” instead of “cats”.
  • Use lowercase for your model name. This is something I think some folks may disagree with. In fact, when you create a LoopBack application and use the sample with a notes API, it capitalizes both Notes and User. In general, most APIs I’ve seen use lowercase, with Microsoft-based APIs being the only real notable exception. As it stands, you shouldn’t use “User” yourself in your application but rather extend it with your own user model (this is discussed further later in the article). When you do, you can use a lowercase name.
  • Use camel case for your names. Given a complex name, like “postal address”, use camel case for the name: “postalAddress”.
  • Be consistent in your relationships. Consistency is always good, but what do we mean here? Consider two APIs, one for cats, and one for owners. A cat has an owner. A owner has many cats. When you define your relationships, you should use a name that makes it obvious what you’re pointing to. So given that an owner has many cats, when you name that relationship, LoopBack is smart enough to suggest “cats”, which is what you should use, instead of something more generic, like “pets”. By using the same name, you don’t have any guesswork into what the relationship is connecting. In fact, if you were to define such a relationship, the LoopBack Explorer provides no visual cue that “pets” is actually a list of cats. You would need to define this yourself in your own documentation.
  • Be consistent in your properties. Yes, it’s that “C word” again. When defining properties, be consistent across your models. If your cat API has a “name” property, then your owner should also have a “name” property. If your cat API has an “age” property, don’t use “howOld” for your owner API.

Properly presenting your properties

After you’ve named your model, the next step is to define the properties that make up that model. As before, here are some suggestions.

  • Be consistent in your types. Yes, again, if “age” represents a number, then it should (in general) represent that across your APIs.
  • Be consistent with your requirements. If your cat model has defined “name” as a required property, then your owner model probably should follow suit. This particular suggestion won’t necessarily always apply, but in general you should look to follow the same settings across your models for similarly named properties.
  • Be consistent with your defaults. By now you’re probably getting kind of mad at me. Good. Building stuff the right way is work. No one’s going to build the next great Cat-based social media network by skimping on the details. If you use a default for a property, like “gender” being “female”, then try to use the same defaults across models.
  • Know when to make things required. This is a tough one. How do you determine when a property value should be required? You need to consider how your users will be interfacing with the API. Imagine a hypothetical “chicken” API. Not to get too gross, but you may not know the gender, immediately, of a new chicken. Therefore you may want to allow your API to accept a new Chicken object and not require a gender, even though typically that would be an important value. In this particular case, you may set up your API to allow for chickens without a gender to be created, but only chickens with a gender to be retrieved by anonymous users.

    A good question to ask may be, “Should everything be required by default, or not?” On one hand, making required be the default may lead to more consistent, useful data. On the other hand, a property that is required may be implicitly considered more important by the end user. There isn’t necessarily a best answer here.
  • Use the most appropriate type. When you define a property, you have many different types you can choose from, including “any” which will allow, well, nearly everything. But try your best to be as specific as possible. You can use “String” for age. You can also use “String” for dates. But LoopBack supports both a “Number” and “Date” type that you should use instead. Your API will be more clear about what type of data it represents and you also get firmer control over what the user will input.

    You can also create a property of type “object”. This allows you to store a generic object as your property value. So for example, I could store name as {“first”:”Raymond”, “last”:”Camden”}. In LoopBack this is called an “anonymous” model. While possible, I’d suggest anything bigger than 2-3 properties should be given it’s own proper model definition. You can find a complete list of property types here: http://loopback.io/doc/en/lb2/LoopBack-types.html

“But wait – there’s more…”

Here are a few more tips to help you along the way.

  • LoopBack provides a query syntax that lets you slice and dice your data in many ways. Given you have an API of cats with properties “name”, “gender”, “age”, and “breed”, your API, out of the box, supports returning all male cats under 5 years old that are Siamese. While this is cool, the syntax may be a bit hard for some consumers to use. Luckily, LoopBack provides two alternatives.

    The first is to simply define a remote method. You can create a remote method that has an end point of /cat/maleSiamese as a short hand for querying for cats that are male and Siamese. You can read more about that here: http://loopback.io/doc/en/lb2/Remote-methods.html

    Another example is the “scope” feature. Model definitions can have multiple “scopes” which can act as filters on your data. You simply provide a name for a scope and data to use as a filter and LoopBack will automatically create a new remote method for you. You can read more about this feature here: http://loopback.io/doc/en/lb2/Model-definition-JSON-file.html#scopes

    When this makes sense will be up to you. One way to determine if a shorthand filter makes sense is to look at your analytics data. Don’t forget that IBM API Connect gives you this out of the box!
  • The in-memory datasource is incredibly useful during early development. It lets you rapidly prototype without setting up a “proper” persistence system. While not appropriate for production, you can certainly use it when beginning development of your APIs. But while it is easy to use, every time you restart your LoopBack application, all of your data will be lost. This is especially problematic if you are using something like nodemon (https://github.com/remy/nodemon) to monitor your project files and automatically restart when a file has changed. You can get around this by simply adding the “file” property to your in-memory datasource definition. LoopBack will then persist your data to a simple flat file.
  • Out of the box, all your APIs are 100% open. That means when you define a cat API, anyone can create, read, update, and delete your data. This is great for prototyping, but not so great for production. The entire security topic is a bit much for this article, but keep in mind that you will absolutely 100% want to lock down your APIs before you move to production. In general, the basic idea is that first you lock everything down. Everything. No one can do anything. Then you gradually open up the API bit by bit. So for example, anonymous users can read. Logged in users can create and super special sparkly users can delete. You can read more about the security models and authorization at the docs: http://loopback.io/doc/en/lb2/Authentication-authorization-and-permissions.html

Join The Discussion

Your email address will not be published. Required fields are marked *