Skip to main content
Skip table of contents

Backend Endpoint Tutorial and Module Guidance

Last Updated: January 7, 2025

This guide covers how to use Rails Engines (modules) in vets-api and when they might be appropriate for your application. Modules can help separate concerns but come with trade-offs. It also includes steps for generating backend endpoints.

Module guidance

Does your application need to be in a module?

Some applications in vets-api organize their code into Rails Engines (which we refer to as modules). While this approach can help separate concerns and provide organizational clarity, it’s important to note that our implementation of Rails Engines differs from typical Rails conventions. These differences may create unexpected friction or require additional effort to adapt, so using modules is not a one-size-fits-all solution and is not a requirement. Keep in mind that it’s possible vets-api will migrate towards a hybrid microservices architecture.

To help decide if splitting your code into a module is the right choice, consider these questions:

  1. Separation of concerns: Does your code represent a distinct domain or feature that could benefit from being isolated from the rest of the application? If so, +1 for modules.

  2. Collaboration and ownership: Will your team primarily own and manage this code? If so, +1 for modules.

  3. Reusability: Is this code likely to be reused across multiple applications? If so, -1 for modules.

  4. Complexity: Are you prepared to manage the added complexity of maintaining a module? (For example, navigating duplicated code, dealing with less conventional Rails Engine behaviors, and ensuring clear boundaries between modules.) If so, +1 for modules.

  5. Refactoring Overhead: Will placing this code in a module increase the cost of refactoring or hinder development velocity for your team or others? If so, -1 for modules.

Modules can be a powerful organizational tool, but they also introduce trade-offs. Consult with other teams who have implemented modules to learn from their experiences.

Tips from a team that moved from main app to a module

Consider URL convention. When mounting an engine in the main app, the convention for the url pattern is {base_url}/{module_name}/{version}/{path_to_controller_action}, where the non-engine version would be {base_url}/{version}/{path_to_controller_action} (without module_name). The frontend code in vets-website does not expect anything between the base_url and the version. Getting around this can be tricky.

Run your module tests alone and simultaneous with the main app tests. To ensure you are really getting your code isolated in the module, you want to be able to set up your rspec tests so they do not depend on any of the test helpers in the main spec folder, because those load big chunks of the main app that your module theoretically should not depend on. (And anything from the main app you do depend on, you want to declare explicitly in your tests). But because of the way tests are run on CI, the entire main app test context gets loaded along with the module test context. Name collision problems can show up here that don’t show up when the module tests are run during local development.

Backend endpoint tutorial

Generating an endpoint

Creating a service backend endpoint for VA.gov is a common task for developers. Due to the complexity of integrating with legacy VA REST or SOAP applications we've developed a pattern for making these connections. To show the parts of the process that are automated, we've written a Rails generator that creates an example 'Hello, World!' endpoint for you.

Generating an endpoint is similar to using the built-in Rails generators that create models, controllers, or migrations for you. The first step is to ensure you're in the root directory of the vets-api project. From there you'll run rails generate module <module_name>. The <module_name> option is the name of the Rails Engine or module that the endpoint will live within. It's also used as a Ruby namespace for the classes that are generated. If your module's name is 'foo' you'd run the command below to generate an endpoint:

rails generate module foo

What gets generated

An endpoint on VA.gov consists of a controller, model, serializer, and service classes. In addition some configuration files are generated. Other existing configuration files, such the main config/routes.rb file, are modified. When the command runs the first section of the output lists the generated and modified files:

CODE
create  modules/foo/lib/foo/engine.rb
create  modules/foo/lib/foo/version.rb
create  modules/foo/lib/foo.rb
create  modules/foo/Rakefile
create  modules/foo/README.rdoc
create  modules/foo/bin/rails
chmod  modules/foo/bin/rails
create  modules/foo/spec/spec_helper.rb
create  modules/foo/config/routes.rb
create  modules/foo/foo.gemspec
create  modules/foo/Gemfile
insert  spec/spec_helper.rb
insert  spec/simplecov_helper.rb
insert  Gemfile
insert  config/routes.rb
run  bundle install from "."
🙌 new module generated at ./modules/foo

Note that you may need to scroll up within the terminal to see the list of files. The bundle command is run for you to ensure the module is installed in the host application, and its output is bookended by the generator's messages.


JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.