Learning Postman

Learning Postman Stepping Up Rails

Beginner

Let’s examine Postman, a desktop app that you use when you want to build a Rails API.

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

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.

Basic Postman request

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 showing GET request

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 needs routes to work, which is easiest to do with the resources keyword. This creates 5 routes automatically for new, create, edit, update, and destroy. 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 Showing GET request
Postman successful request for a many things

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 showing GET request

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 showing Headers
Postman request showing no headers

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 showing response
Postman response if no API-KEY is passed

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

Rails terminal output

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 response when the API-KEY is correctly passed

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.