Skip to content

20 API Introduction

Dave Strus edited this page Nov 18, 2014 · 3 revisions

Creating a REST API with JSON

We want to be able to get at our notes programmatically through other applications—say, a different web app or a mobile app. Rails gives you all the pieces you need to do that with a minimum of pain.

Because Rails encourages use of a RESTful pattern for resource-based controllers with standardized CRUD actions, it makes it easy to accept & return JSON, or even XML.

Looking back at elevenpeeps, we can see that the scaffold generator takes advantage of this built-in functionality. If you were to make requests to http://localhost:3000/chirps.json, you should see a JSON response in your browser.

If viewing JSON in a web browser is something you do often, try installing JSON Formatter for Chrome.

If you take a look back at the scaffolded chirps_controller.rb in ElevenPeeps, you'll notice that the create, update, and destroy actions each have a respond_to block, and some of the actions have .json.jbuilder views.

Let's take a look at the source in elevenpeeps for a minute to see what it's doing.

app/controllers/chirps_controller

class ChirpsController < ApplicationController
  before_action :set_chirp, only: [:show, :edit, :update, :destroy]

  # GET /chirps
  # GET /chirps.json
  def index
    @chirps = Chirp.all
  end

  # GET /chirps/1
  # GET /chirps/1.json
  def show
  end

  # GET /chirps/new
  def new
    @chirp = Chirp.new
  end

  # GET /chirps/1/edit
  def edit
  end

  # POST /chirps
  # POST /chirps.json
  def create
    @chirp = Chirp.new(chirp_params)

    respond_to do |format|
      if @chirp.save
        format.html { redirect_to @chirp, notice: 'Chirp was successfully created.' }
        format.json { render :show, status: :created, location: @chirp }
      else
        format.html { render :new }
        format.json { render json: @chirp.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /chirps/1
  # PATCH/PUT /chirps/1.json
  def update
    respond_to do |format|
      if @chirp.update(chirp_params)
        format.html { redirect_to @chirp, notice: 'Chirp was successfully updated.' }
        format.json { render :show, status: :ok, location: @chirp }
      else
        format.html { render :edit }
        format.json { render json: @chirp.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /chirps/1
  # DELETE /chirps/1.json
  def destroy
    @chirp.destroy
    respond_to do |format|
      format.html { redirect_to chirps_url, notice: 'Chirp was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_chirp
      @chirp = Chirp.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def chirp_params
      params.require(:chirp).permit(:content)
    end
end

It's great to be able to have different responses to the same controller action/route, but if you need to have a standardized interface for third-party integrations, then it's best not to have API code mixed in with your web application code.

As we go through our codebase to make future changes and enhancements, it becomes hard to keep ourselves from breaking or changing our API. Even if we manage (with help from automated tests) never to break that API, we can still end up with little islands of code we don't like that must be there just to avoid breaking the API.

We're not going to follow the scaffolded example when writing the API for ElevenNote.