Playing With Postman

iStock-508412190-945x630.jpg


Saturdays & Sundays are debugging days at The Rails Coach! Well, every day is a debugging day but on Saturdays and Sundays, we focus on learning specific debugging tools. 


This post will review Postman for MacOS (but there is a Windows version too). The latest version of Postman comes with some annoying adware as upsells, but you can get started with the basics for no cost.

First, download and run the installer from here.

When you first open Postman you will see a window greeting you


Postman-2020-05-07-17-57-33-1-1024x506.jpg

Click the + button to open a new window.

Today we’re going to send requests, or specifically JSON requests, to our local development server that will respond under certain conditions.

Think of Postman as though it — and by extension you as its operator — acts in place of a 3rd party app that is accessing your API. Alternatively, you can test an API you are writing in Rails for a mobile or client app.

A request means a call (or an “ask & respond” cycle) that is 1) sent over HTTP or HTTPS, 2) is for a specific type of format (html, json, js, or XML), and 3) is made from a client to a server for a specific uniform resource indicator (or URI). A URI is what you commonly call a full URL, but in the context of APIs we call it a URI to because URI is more general that URL, but conceptually they are the same thing.

Example

In our example, we’ll use as our endpoint:

http://localhost:3000/things.json

To test it out, you’ll need of course to be running a test Rails app on your machine.

When we send a request to /things.json, we expect to get back a JSON array of Things in our Rails app.

The request has the key components discussed above and two more: The Headers, which operate automatically in the transmission between the client & server, and the Parameters.

Finally, to incorporate a 6th dimension, each request has a HTTP method (which are any of GET, POST, PUT, PATCH, OPTIONS, etc)

In other words, let’s consider all of the parts of the request in this exercise.

Rails handles all of this on the back end for you — thankfully! — making it easily available to your Controller. We won’t go over that today, but the code that makes this work is pretty straightforward and I will show you that.

Headers

Headers are typically used for authentication in the context of an API key, which the user either retains indefinitely or the front-end code maintains a logged-in/logged-out state and the API key.

Before 2011, it was common to see an “X-“ in front of custom (that is, non-standard) header in some apps. That is, if you were implementing an API header for your own app, passing an API key, you may have chosen to call it X-API-KEY

The X- prefix in the header was used in the early days to differentiate it from a ‘standard’ header. However, you no longer need to use the X- prefix in your Header names. That’s because the W3C decided there was no such important difference between your header names and any ‘standard’ ones, so just drop the X- and call it API_KEY, or whatever else describes it for you in your app.

You no longer need to use the X- prefix in your Header names. Instead of X-API-KEY, just call it API-KEY

Parameters

First, let’ see what a basic request look like from Postman.


Postman-2020-05-07-18-11-39-1024x436.jpg

You’re about to send a request from Postman to your webserver. Make sure the server is running (bundle exec rails s).

Let’s pause and notice two things here: One, the drop-down to the left of the URI where it says “GET.” Two, notice that there are no parameters listed under the “Parameters” tab


Postman-2020-05-07-18-14-09-1024x436.jpg

That’s important because we’re currently making a GET request to the endpoint, and we have no parameters.

Making a Basic Request with Postman

Our Rails app only needs a route… (config/routes.rb)

Rails.application.routes.draw do

  resources :things

end

A model

class Thing < ApplicationRecord
end

by the way, we had a migration that looked like:

class CreateThings < ActiveRecord::Migration[6.0]
  def change
    create_table :things do |t|
      t.string :name
      t.string :category
      t.timestamps
    end
  end
end

And finally a controller

class ThingsController < ApplicationController
  def index
    @things = Thing.all
    respond_to do |format|
      format.json { render json: @things.as_json }
    end
  end
end

Hit send and… Boom! You’ve got yourself a postman request. (You will see I have some dummy data in here.)


Postman-2020-05-07-18-31-16-1024x727.jpg

GET requests are used by endpoints to query for lists and to query against, for example, a URL where the ID of the thing was part of the URL. For example, with a small modification to this controller, we can use the edit route to query for just a single item:

class ThingsController < ApplicationController
  def index
    @things = Thing.all
    respond_to do |format|
      format.json { render json: @things.as_json }
    end
  end


  def edit
    @thing = Thing.find(params[:id])
    respond_to do |format|
      format.json { render json: @thing.as_json }
    end
  end
end

In other words, we want to have both an edit and a list (index) endpoint for this API.

Now, our URI will be

http://127.0.0.1:3000/things/1/edit.json

If we “hit” the server now, we get just the Apple record


Postman-2020-05-07-18-38-22-1024x727.jpg

Notice that up until this point, we’ve not used any query parameters and only used GET requests.

Making A Request with Postman That isn’t a GET Request

In any RESTful application, you should follow the rules of the HTTP verbs:

Create— Use a POST verb

Read— Use a GET verb

Update— Use a PUT or PATCH verb*

Delete— Use a DELETE verb

That’s what you do. Don’t make up your own verbs for defining routes. In Rails, we did this already when we defined resources :things in our routes.rb file. When we did that, we got these four CRUD (create-read-update-delete) actions along with the index action automatically. You can examine your routes with bundle exec rake routes

For our simple GET request that returned the list of Things (above), we had no parameters. That’s ok, we didn’t need any.

To understand how to make a POST request, we also need to understand how parameters work.

Making a Postman Request with Parameters

Now, with Postman, switch your method to POST and change the URI back to the index view http://127.0.0.1:3000/things.json

Not so fast cowboy! You need to give Rails the data for the Thing you want to create in the parameters.

{name: "Apple", category: "Fruit"}

Now hit Send.

You can see in your Rails app that a new thing is sent.

You can use parameters with either GET or POST! Above all, just remember that with POST, your parameters are sent in the body of your request, and with GET, you’ll see them in the query section (by the URL).

Now With a Header API Key

Let’s quickly review how to pass a header. Do not confuse headers with parameters — they are different. Headers operate automatically in the HTTP transmission. Like parameters, they can communicate information from the client to the server. Unlike parameters, they can also let the server respond with information too.

You’ll note also that Headers are a native part of the HTTP protocol, whereas parameters are a construction of your app (that is, Rails) and the web requests between client & server.

We’ll call it API-KEY.

That’s the name of the header. In Postman, you’ll want to switch into the HEADERS tab:

In Rails, let’s add this code to our controller

skip_forgery_protection

before_action :authenticate_access


def authenticate_access
  api_key = request.headers['API-KEY']

  # assume you have an Account table with a field api_key
  if ! Account.where(api_key: api_key).any?
    raise Account::NotAuthorized
  end
end

To do this correctly, we’ll actually need to add a little more Rails magic here to handle the authentication. You can authenticate your user in any way you like. While there are many ways to implement authentication, I am doing something similar to the basic way shown in the Rails guides.

Handling the Exception

First, move up to your ApplicationController and add the method that will handle the exception, like so

class ApplicationController < ActionController::Base
  private

  def account_not_authorized
    flash[:error] = "You don't have access to this section."

    respond_to do |format|
      format.json {  render json: {"response": flash[:error]}}
      format.html {   render flash[:error], layout: false}
    end
  end
end

Now, go back down to your ThingsController and add rescue_from Account::NotAuthorized, with: :account_not_authorized so your new ThingsController will look like this

class ThingsController < ApplicationController

  skip_forgery_protection

  before_action :authenticate_access
  rescue_from Account::NotAuthorized, with: :account_not_authorized

  def authenticate_access
    api_key = request.headers['API-KEY']

    # assume you have an Account table with a field api_key
    if ! Account.where(api_key: api_key).any?
      raise Account::NotAuthorized
    end
  end

  def index
    @things = Thing.all
    respond_to do |format|
      format.json { render json: @things.as_json }
    end
  end


  def edit
    @thing = Thing.find(params[:id])
    respond_to do |format|
      format.json { render json: @thing.as_json }
    end
  end
end

After that, switch back to Postman and let’s give it a whirl. Notice that we’ll first try with no Headers:


Postman-2020-05-08-08-12-13-1024x800.jpg

After that go ahead and hit that “Send” button and notice how Rails tells you that you aren’t authorized— doh!— because we didn’t pass it an API-KEY.

Postman-2020-05-08-08-14-08-1024x800.jpg

Let’s drop into our Rails console with bundle exec rails c and make a new Account using Account.create(api_key: "abcdefghijklmnopqrstuvwxyz")

playing-with-postman-%E2%80%94-ruby-bin-rails-c-%E2%80%94-89%C3%9715-2020-05-08-08-17-32-1024x476.jpg

Go back to Postman and in the HEADERS make sure to set API-KEY to abcdefghijklmnopqrstuvwxyz

Now hit the Send again with the API-KEY set, and Bob’s your Uncle, you get a valid response.


Postman-2020-05-08-08-19-44-1-1024x800.jpg

I hope you’ve enjoyed this debugging session with Postman. In conclusion, it’s a great tool especially when you are working with JSON responses as most modern APIs do. Getting used to it as an alternative to your browser is a skill every new Rails developer should take on.



EXAMPLE APP FOR THIS POST CAN BE FOUND AT

https://github.com/the-rails-coach/playing-with-postman


ASSIGNMENTS


  1. Create a simple Rails app that has both GET and POST requests. Send your GET endpoints parameters in the query string. Send your POST request as in Postman.
  2. Consider how Postman can be used to query against other people's APIs. How can you displace whiteness or work towards racial justice using APIs? What can you learn about structures and how structures of APIs work to center whiteness? How can Postman be used to work towards racial justice?
  3. Make a speical header that nobody's ever heard of. Name it something unique, but don't start it with X-. Consider how naming things centers whiteness in the narrative about our shared experiences.
  4. Test your Rails app that receives this special controller with Postman to send your special header along with the request. Handle the error case first and then handle the normal (success) result.
  5. Consider ways you can work towards racial jusitce elevating black and brown voices and centering black and brown narratives, using Rails, an API, or Postman in the process.