API Engineering

API Engineering

Apr 8, 2022 8:18 AM
Well Documented
APIRuby on Rails

API Engineering


  • APIs should be easy to understand that there shouldn’t be a need for UI onboarding
  • To follow a specific process/format to make the API understanding easier
  • To set a standard for everyone to be in sync in API understanding
  • Letting know the whole front-end team to be aware of new APIs or API changes without having to draft these (slack) messages and tumble on the message format every time
  • Avoid follow-ups in knowing if an API or API change is upon staging/prod
  • Keeping the frontend and backend together to lessen the chances of such miscommunications, facilitating smooth application development
  • Achieve complete coherence of the teams working on the project

Have a Changelog project

Goal: Letting know developers of any new features, improvements, and changes that have been made to an API

What is Changelog?

  • Managing public APIs where front-end developers or third party developers who need to be kept in the loop of new features or changes on the platform
  • Store a list of updates to platforms for power users who are interested in feature updates

Steps on how to use Changelog:

  1. Create a project aligning it to a company
  2. Navigate to the projects section
  3. Create a log on entering 🎯 Regarding an API, API developers need to give (UI devs) full context in the description, on what to do with the API. This includes providing screenshots pointing to each field and describing what it needs to be used for (if not clear from the documentation). Below are two reference logs as such:
    • Title - Title of the log
    • Category - Category could be a New feature, Improvement, Bug, Breaking change, Fix
    • Description - Description of the log
    • Log 1
    • Log 2
  4. Subscribe to a project you would wish to receive updates in Below is an image of a log with log title, type of update (category), and description of the log
  5. image


Documentation is a first‐class feature of GraphQL type systems. To ensure the documentation of a GraphQL service remains consistent with its capabilities, descriptions of GraphQL definitions are provided alongside their definitions and made available via introspection.

Description for field

Descriptions can be added with the field(...) method as a positional argument, a keyword argument, or inside the block.

  • 3rd positional argument
  • field :name, String, "name of this thing", null: false
  • description: keyword
  • field :name, String, null: false,  description: "name of this thing"
  • Inside the block
  • field :name, String, null: false do   description "name of this thing"end

Description for argument

  • Write description for argument
  • argument :first_name, String, "Description goes here - First name of the user", required: true
  • Define arguments that are required vs optional
  • Required arguments

    argument :category, String, required:true

    Optional arguments

    argument :category, String, required:false 

    Note: If all arguments are optional it leads to ArgumentError, to prevent this, you must either specify default_value for all keyword arguments or use the **args double splat operator argument in the method definition

Defining Enum Types
  • In your application, enums extend GraphQL::Schema::Enum and define values with the value(...) Method:
  • # app/graphql/types/base_enum
    class Types::BaseEnum < GraphQL::Schema::Enum 
    # app/graphql/types/media_category.rb
    class Types::MediaCategory < Types::BaseEnum
    	value “AUDIO”, “An audio file, such as music or spoken word” 
    	value “IMAGE”, “A still image, such as a photo or graphic”
    	value “TEXT”, “Written words” value “VIDEO”, “Motion picture, may have audio” 

Each value may have:

  • A description (as the second argument or description: keyword)
  • A deprecation reason (as deprecation_reason:), marking this value as deprecated
  • A corresponding Ruby value (as value:), see below:
  • By default, Ruby strings correspond to GraphQL enum values. But, you can provide value: options to specify a different mapping. For example, if you use symbols instead of strings, you can say:

    value "AUDIO", value: :audio

    Then, GraphQL inputs of AUDIO will be converted to :audio and Ruby values of :audio will be converted to "AUDIO" in GraphQL responses.

  • Defining GraphQL enums dynamically from Rails enums
  • module Types 
    	class IssuableSeverityEnum < BaseEnum 
    		graphql_name 'IssuableSeverity'
    		description 'Incident severity'
    		::IssuableSeverity.severities.keys.each do |severity|      
    			value severity.upcase, value: severity, description: "#{severity.titleize} severity."    

Description for Type

Write descriptions for Types

class ExampleType < Types::BaseObject  
	description "description goes here"

Description for Query

Write description for Query

class ExampleQuery < Queries::BaseQuery  
	description "description goes here"

Descriptions for Mutations

Write descriptions for Mutations

class ExampleMutation < Mutations::BaseMutation  
	description "description goes here"

Handle deprecation

Fields deprecation

  • Deprecated fields can be marked by adding a deprecation_reason: keyword argument
  • field :name, String, null: true,
      deprecation_reason: "We split up the name into two; firstname and lastname"
  • Have the deprecated field logged on Changelog
  • Include the applicable Deprecated field, Reason, Date of deprecation, and Date of removal in the description of the log.


Arguments deprecation

  • Deprecated arguments can be marked by adding a deprecation_reason: keyword argument:
  • argument :name, String, required: false, deprecation_reason: "Use `first_name` instead."
    argument :first_name, String, required: false

    ⚠️ Note: argument deprecation is a stage 2 GraphQL proposal so not all clients will leverage this information.

  • Use as: :alternate_name to use a different key from within your resolvers while exposing another key to clients.
  • field :post, PostType, null: false do 
    	argument :post_id, ID, required: true, as: :id
    def post(id:)
  • Have the deprecated argument logged on Changelog