Every major online service nowadays offers an API. Shorthand for Application Programming Interface, it provides developers programmatic access to the service. There are different types of APIs, but most boil down to RESTful, JSON APIs. If you’re planning on building an app, adding an API should definitely be in your roadmap.
In this article, we’ll be building an API as an interface to Cowsay. Users of the API will be able to send a text and customize it using different parameters accepted by the Cowsay program. We’ll later deploy this API to Heroku and publish it to RapidAPI so it’s easier for other developers to find it.
What we will need
For this tutorial, you will need Ruby (preferably 2.6) and Ruby on Rails. Both are relatively easy to install, but the procedure depends on the platform you’re on. To install Ruby, refer to the official website for instructions. Installing Rails is also pretty simple: you can use their official installation guide.
Other than that, you’ll need your favorite code editor. I personally prefer Visual Studio Code, but feel free to use the editor you’re most comfortable with.
Setting everything up
Since we’re going to be building an API, we don’t exactly need everything Rails offers. We won’t be rendering HTML views, for example. Fortunately, Rails’ application generator offers an option to create a more “lean” version of a Rails app, where only the necessary modules for an API are installed. This can be further customized depending on your needs. In our case, we’ll generate a new API project, and also skip ActiveRecord, since we won’t be needing to store anything in a database.
rails new cow_say --api --skip-active-record
After this command is done, we’ll need to add two more gems to our Gemfile
:
# Gemfile gem 'ruby_cowsay' gem 'jbuilder'
The first gem is what will allow us to serve Cowsay to our API clients. It’s a ruby implementation of the famous program. The jbuilder
gem simplifies serving JSON in our API, by allowing us to build payloads using plain ruby. Make sure you run bundle install
to get the gems.
Adding the Controller and Route
For now, our API will only have one endpoint: /say
. Clients will POST to this endpoint with a set of parameters, and get a response back from us. Let’s add this endpoint to our routes file:
# config/routes.rb Rails.application.routes.draw do post 'say', to: 'cow#say' end
What this is saying is, take a POST to /say
and route it to the method say
in CowController
. Now we need to create our controller and method:
# app/controllers/cow_controller.rb class CowController < ApplicationController def say @message = Cow.new.say(params[:message]) end end
Very simple method here. For now, all we do is create a message from the parameters and assigning it to the @message
instance variable. We will later add some validation and more options. In order to render this and show this to our API clients, we’ll need to create a view. Just like in a regular Rails app, JSON responses are rendered using views, but, instead of using ERB (embedded Ruby) to generate an HTML response, we’ll be using Jbuilder to generate a JSON response:
# app/views/cow/say.json.jbuilder json.message @message
Our view doesn’t really need more than this. Jbuilder’s documentation will help you if you get lost here, but this basically tells it to create a root property called message
in the JSON response, and assign the @message
instance variable to it. Jbuilder has a lot more to offer than just this extremely simple rendering, so we recommend going over their documentation.
Testing our API
We’ve already built our API! In order to test it, you can use Postman or Insomnia. For the purposes of this tutorial, we’ll just rely on curl. Boot up the Rails server first:
rails server
Wait until your server is running, then in another terminal, run a curl command to test the new endpoint:
curl localhost:3000/say -H 'Content-Type: application/json' -d '{"message": "Hello from RapidAPI"}'
This command POSTs the JSON payload with the string “Hello from RapidAPI” to our say
endpoint. If everything goes right, you’ll get something like this:
{"message":" _____________________ nu003c Hello from RapidAPI u003en --------------------- n ^__^n (oo)_______n (__) )/n ||----w |n || ||n"}
This doesn’t really look like much, but that’s only because of the formatting. We can use a quick trick using ruby to parse the JSON response and print the result. Run this:
curl localhost:3000/say -H 'Content-Type: application/json' -d '{"message": "Hello from RapidAPI"}' | ruby -r json -e "print JSON.parse(STDIN.read)['message']"
Here we’re piping the output of our curl command into ruby, where we require the json
module and use it to parse the response, grab the property and print
it, which makes sure the response is presented correctly. You should now see a cow saying your sentence:
More Parameters and Validation
So far our API is simple. Perhaps too simple. Let’s take it up a notch. The Cowsay gem we’re using accepts a bunch of parameters to customize what it generates. For example, it doesn’t have to be a cow saying something, it can be a dinosaur. You can also change the text bubble to a thought bubble. Furthermore, our cow can even look paranoid! Change the say
method in our cow controller to this:
# app/controllers/cow_controller.rb class CowController < ApplicationController def say message = params[:message] cow = params[:cow] || 'cow' balloon_type = params[:balloon_type] || 'say' face_type = params[:face_type] || 'default' @message = Cow .new(cow: cow, face_type: face_type) .say(message, balloon_type) end end
We’re assigning our parameters to variables for easier use later. Plus, we’re setting some defaults so our users don’t have to specify something when not necessary. Our default will just be a cow saying the sentence with a normal face. Let’s put this to the test:
curl localhost:3000/say -H 'Content-Type: application/json' -d '{"message": "Hello from RapidAPI", "cow": "stegosaurus", "balloon_type": "think"}' | ruby -r json -e "print JSON.parse(STDIN.read)['message']"
This should get you a nice dinosaur:
While we’re at it, let’s add some validation to our API. Only some parameters should be allowed, and the message
parameter should be required. This is easy using Rails’ strong parameters:
# app/controllers/cow_controller.rb class CowController < ApplicationController def say params.require(:message) params.permit(:cow, :balloon_type, :face_type) message = params[:message] cow = params[:cow] || 'cow' balloon_type = params[:balloon_type] || 'say' face_type = params[:face_type] || 'default' @message = Cow .new(cow: cow, face_type: face_type) .say(message, balloon_type) end end
Notice the highlighted lines. Here we require
that the message
parameter is present, and we only allow the cow
, balloon_type
and face_type
options to be present. The rest get discarded by Rails. Now, feel free to play around with your API. You can get any of these cows in your responses. Note that not all support different face types.
How to Publish your API on RapidAPI
RapidAPI is a marketplace of APIs, which makes discovering them extremely easy. It’s also possible to use different APIs using one single SDK, and payment is bundled into one single account. But first, your app needs to be hosted somewhere. Let’s start with that.
Deploying to Heroku
The easiest way to host this API is Heroku. If you’re not familiar with them, they offer an extremely convenient way to host projects. Deployment is also just as easy. Just run a command on your terminal and they do the rest. Go ahead and sign up if you haven’t already. You’re then going to need to install the Heroku CLI. Installation depends on your platform, so check out the different options here. After that, go ahead and log in to Heroku on your terminal and follow the instructions:
heroku login
After you’re done, go ahead and run heroku create
in the same directory as the Rails app. This will create a new application on Heroku and give you a domain. It will also configure your Git project (Rails automatically creates one for you) so that you can deploy to Heroku by just running git push
. Since Heroku relies on Git and our repository’s history, we’ll need to commit our progress. If you’re not familiar with Git, go ahead and check out the learning resources on GitHub.
git commit -a -m "Initial commit"
Now, run git push heroku master
on your terminal. This will push our main branch to Heroku and deploy our app. You’ll see something like this when the command finishes:
remote: -----> Launching... remote: Released v4 remote: https://nameless-river-12345.herokuapp.com/ deployed to Heroku
Your API is now on Heroku! You can try the same curl commands we tried before, just replace https://localhost:3000
with the URL of your Heroku app.
Publish on RapidAPI
Now that your API is online, we can add it to RapidAPI. Head on to RapidAPI and click on “Add your API” on the top right. Enter a name and a description for your API, and select a category.
We need to configure our API first. Click on “Settings” at the top, then set the “Base URL” to your Heroku app root endpoint (the one you got just before). Next, we’ll need to configure some Transformations. Down below, click “+ Add Secret Header or Parameter”. For the name, set it to Content-Type
and for the value, set it to application/json
. Now add another header, but this time set the name to Accept
and the value to application/json
as well. These are headers that are sent by RapidAPI to our API, so it knows how to read the parameters clients send to it.
Over at the top again, click on “Endpoints”, then click on “+ Create Endpoint”. Here, define a name for the endpoint (something like “Say”, for instance), then set the method to POST
and the path to /say
. Further down, next to “Payload”, click on “Add Model”. Here you can just specify a name (“Payload” will suffice in this case), and a sample body. In our case, we’ll use this:
{"message": "Hello from RapidAPI", "cow": "stegosaurus", "balloon_type": "think"}
Now go ahead and click the “Save & Test Endpoint” button. After a few seconds, you should get a response back. You’re all set!
Conclusion
In this article, you learned how to create an API using Ruby on Rails. You also learned how to deploy it to Heroku and publish it on RapidAPI. We recommend you read up on how to set up a database on Heroku so you can add that capability to your APIs. Also, check out RapidAPI’s documentation on publishing APIs so you get a better understanding of all the options.
Related Articles
- How to use an API
- How to Create an API
- How to Send SMS with Ruby
- Convert Rails App into API
W pizdu taka robota!
It not works.
Not only is ruby_cowsay not available from a public gemserver, the only output is:
json.message @message
“`
curl localhost:3000/say -H ‘Content-Type: application/json’ -d ‘{“message”: “Hello from RapidAPI”}’
“`
Good software is the result of good QA. Did you test this?
Hi Lane,
I’m sorry to hear it’s not working for you. I’m curious as to why you mention the gem is not available from a public gemserver, since rubygems.org has this gem published here: https://rubygems.org/gems/ruby_cowsay. Are you getting some sort of error when installing the gem? What happens if you do `gem install ruby_cowsay` directly in your terminal?
I’m also curious to hear how it is you’re getting that output. You should definitely not get the output of the template, if that’s what you meant with your comment. Would you perhaps paste the contents of the `CowController`? How is it that you’re reproducing this?
Let me know!
Hi and thanks for this useful article !
Just wondering, what is the purpose of the ‘module CowSay’ thing within the config/applications.rb file ?
Thanks.
Hi! Thank you for your post!
The following lines are giving an error :
error message:
curl localhost:3000/say
-H ‘Content-Type: application/json’
-d ‘{“message”: “Hello from RapidAPI”}’
{“message”:null}zsh: command not found: -H
zsh: command not found: -d
Did I skip something?
Thanks! Runs perfectly and very concise tutorial. Just what I was looking for! It’s so hard to find good examples like these.
Hi! Thank you so much for this tutorial! I was just wondering if we were to test it on Postman, how would we pipe it using ruby to get the desired result?