{"id":209,"date":"2017-06-14T02:43:01","date_gmt":"2017-06-14T02:43:01","guid":{"rendered":"http:\/\/simplecode.xyz\/?p=209"},"modified":"2022-01-10T14:48:32","modified_gmt":"2022-01-10T14:48:32","slug":"rails-api-quick-note","status":"publish","type":"post","link":"https:\/\/simplecode.com.vn\/?p=209","title":{"rendered":"Rails API &#8211; Quick note"},"content":{"rendered":"<h3>1. Setting up Rails 5<\/h3>\n<pre><code>rails new api_app_name --api -d postgresql -T\ncd api_app_name\nbundle install\nrails db:setup\n<\/code><\/pre>\n<p>Note:<\/p>\n<p><code>--api<\/code> : generate API app only<\/p>\n<p><code>-d postgresql<\/code> : using postgresql database<\/p>\n<p><code>-T<\/code> : to skip generating Test because we are going to use RSpec for testing.<\/p>\n<h3>2. Using RSpec for testing<\/h3>\n<pre><code>group :development, :test do\n\n    # Use RSpec for specs\n    gem 'rspec-rails', '3.1.0'\n\n    # Use Factory Girl for generating random test data\n    gem 'factory_girl_rails'\nend\n<\/code><\/pre>\n<pre><code>bundle<\/code><\/pre>\n<pre><code>rails g rspec:install<\/code><\/pre>\n<h3>3. Building your API<\/h3>\n<pre><code>rails g scaffold user name email\nrails db:migrate\n# run the default server on port 3000\nrails s\n<\/code><\/pre>\n<h3>4. Serializing API ouput<\/h3>\n<pre><code>gem 'active_model_serializers'<\/code><\/pre>\n<pre><code>bundle<\/code><\/pre>\n<pre><code>rails g serializer user<\/code><\/pre>\n<pre><code># app\/serializers\/user_serializer.rb\nclass UserSerializer &lt; ActiveModel::Serializer\n    attributes :id, :name, :email\nend\n\nclass ApplicationController &lt; ActionController::API\n    include ActionController::Serialization\n\n    # ...\nend\n<\/code><\/pre>\n<h3>5. Enabling CORS (Cross-Origin Resource Sharing)<\/h3>\n<pre><code>gem 'rack-cors'<\/code><\/pre>\n<pre><code>bundle<\/code><\/pre>\n<pre><code># config\/application.rb\nmodule YourApp\n    class Application &lt; Rails::Application\n\n    # ...\n\n    config.middleware.insert_before 0, \"Rack::Cors\" do\n        allow do\n        origins '*'\n        resource '*', :headers =&gt; :any, :methods =&gt; [:get, :post, :options]\n        end\n    end\n\n    end\nend\n<\/code><\/pre>\n<h3>6. Versioning your API<\/h3>\n<p># GET http:\/\/api.mysite.com\/v1\/users\/<\/p>\n<pre>app\/controllers\/\n.\n|-- api\n|   |-- v1\n|       |-- api_controller.rb\n|       |-- users_controller.rb\n|-- application_controller.rb\n<\/pre>\n<pre><code># app\/controllers\/api\/v1\/api_controller.rb\nmodule Api::V1\n    class ApiController &lt; ApplicationController\n    # Generic API stuff here\n    end\nend\n<\/code><\/pre>\n<pre><code># app\/controllers\/api\/v1\/users_controller.rb\nmodule Api::V1\n    class UsersController &lt; ApiController\n\n    # GET \/v1\/users\n    def index\n        render json: User.all\n    end\n\n    end\nend\n<\/code><\/pre>\n<pre><code># config\/routes.rb\nconstraints subdomain: 'api' do\n    scope module: 'api' do\n    namespace :v1 do\n        resources :users\n    end\n    end\nend\n<\/code><\/pre>\n<h3>7. Rate Limiting and Throttling<\/h3>\n<pre><code>gem 'rack-attack'<\/code><\/pre>\n<pre><code>bundle<\/code><\/pre>\n<pre><code># config\/application.rb\nmodule YourApp\n    class Application &lt; Rails::Application\n    # ...\n    config.middleware.use Rack::Attack\n    end\nend\n<\/code><\/pre>\n<pre><code># config\/initializers\/rack_attack.rb\nclass Rack::Attack\n\n    # `Rack::Attack` is configured to use the `Rails.cache` value by default,\n    # but you can override that by setting the `Rack::Attack.cache.store` value\n    Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new\n\n    # Allow all local traffic\n    whitelist('allow-localhost') do |req|\n    '127.0.0.1' == req.ip || '::1' == req.ip\n    end\n\n    # Allow an IP address to make 5 requests every 5 seconds\n    throttle('req\/ip', limit: 5, period: 5) do |req|\n    req.ip\n    end\n\n    # Send the following response to throttled clients\n    self.throttled_response = -&gt;(env) {\n    retry_after = (env['rack.attack.match_data'] || {})[:period]\n    [\n        429,\n        {'Content-Type' =&gt; 'application\/json', 'Retry-After' =&gt; retry_after.to_s},\n        [{error: \"Throttle limit reached. Retry later.\"}.to_json]\n    ]\n    }\nend\n<\/code><\/pre>\n<h3>8. Authenticating your API<\/h3>\n<pre><code>Authorization: Token token=\"WCZZYjnOQFUYfJIN2ShH1iD24UHo58A6TI\"<\/code><\/pre>\n<pre><code>rails g migration AddApiKeyToUsers api_key:string<\/code><\/pre>\n<pre><code>\nclass User &lt; ActiveRecord::Base\n\n    # Assign an API key on create\n    before_create do |user|\n    user.api_key = user.generate_api_key\n    end\n\n    # Generate a unique API key\n    def generate_api_key\n    loop do\n        token = SecureRandom.base64.tr('+\/=', 'Qrt')\n        break token unless User.exists?(api_key: token)\n    end\n    end\nend\n<\/code><\/pre>\n<pre><code>#  using the built in authenticate_or_request_with_http_token Rails method.\nclass ApplicationController &lt; ActionController::Base\n    include ActionController::HttpAuthentication::Token::ControllerMethods\n\n    # Add a before_action to authenticate all requests.\n    # Move this to subclassed controllers if you only\n    # want to authenticate certain methods.\n    before_action :authenticate\n\n    protected\n\n    # Authenticate the user with token based authentication\n    def authenticate\n        authenticate_token || render_unauthorized\n    end\n\n    def authenticate_token\n        authenticate_with_http_token do |token, options|\n            @current_user = User.find_by(api_key: token)\n        end\n    end\n\n    def render_unauthorized(realm = \"Application\")\n        self.headers[\"WWW-Authenticate\"] = %(Token realm=\"#{realm.gsub(\/\"\/, \"\")}\")\n        render json: 'Bad credentials', status: :unauthorized\n    end\nend\n<\/code><\/pre>\n<pre><code># test\ncurl -H \"Authorization: Token token=PsmmvKBqQDOaWwEsPpOCYMsy\" http:\/\/localhost:3000\/users\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>1. Setting up Rails 5 rails new api_app_name &#8211;api -d postgresql -T cd api_app_name bundle install rails db:setup Note: &#8211;api : generate API app only -d postgresql : using postgresql database -T : to skip generating Test because we are going to use RSpec for testing. 2. Using RSpec for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[10],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v17.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Rails API - Quick note - SimpleCode<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/simplecode.com.vn\/?p=209\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Rails API - Quick note - SimpleCode\" \/>\n<meta property=\"og:description\" content=\"1. Setting up Rails 5 rails new api_app_name --api -d postgresql -T cd api_app_name bundle install rails db:setup Note: --api : generate API app only -d postgresql : using postgresql database -T : to skip generating Test because we are going to use RSpec for testing. 2. Using RSpec for [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/simplecode.com.vn\/?p=209\" \/>\n<meta property=\"og:site_name\" content=\"SimpleCode\" \/>\n<meta property=\"article:published_time\" content=\"2017-06-14T02:43:01+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-01-10T14:48:32+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"simplecode\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/simplecode.com.vn\/#website\",\"url\":\"https:\/\/simplecode.com.vn\/\",\"name\":\"SimpleCode\",\"description\":\"Simple Code\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/simplecode.com.vn\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/simplecode.com.vn\/?p=209#webpage\",\"url\":\"https:\/\/simplecode.com.vn\/?p=209\",\"name\":\"Rails API - Quick note - SimpleCode\",\"isPartOf\":{\"@id\":\"https:\/\/simplecode.com.vn\/#website\"},\"datePublished\":\"2017-06-14T02:43:01+00:00\",\"dateModified\":\"2022-01-10T14:48:32+00:00\",\"author\":{\"@id\":\"https:\/\/simplecode.com.vn\/#\/schema\/person\/b110785905231d29553717dd14b766dc\"},\"breadcrumb\":{\"@id\":\"https:\/\/simplecode.com.vn\/?p=209#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/simplecode.com.vn\/?p=209\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/simplecode.com.vn\/?p=209#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/simplecode.com.vn\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Rails API &#8211; Quick note\"}]},{\"@type\":\"Person\",\"@id\":\"https:\/\/simplecode.com.vn\/#\/schema\/person\/b110785905231d29553717dd14b766dc\",\"name\":\"simplecode\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/simplecode.com.vn\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/22e0b2cc28939e5aecc166195d629442?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/22e0b2cc28939e5aecc166195d629442?s=96&d=mm&r=g\",\"caption\":\"simplecode\"},\"url\":\"https:\/\/simplecode.com.vn\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Rails API - Quick note - SimpleCode","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/simplecode.com.vn\/?p=209","og_locale":"en_US","og_type":"article","og_title":"Rails API - Quick note - SimpleCode","og_description":"1. Setting up Rails 5 rails new api_app_name --api -d postgresql -T cd api_app_name bundle install rails db:setup Note: --api : generate API app only -d postgresql : using postgresql database -T : to skip generating Test because we are going to use RSpec for testing. 2. Using RSpec for [&hellip;]","og_url":"https:\/\/simplecode.com.vn\/?p=209","og_site_name":"SimpleCode","article_published_time":"2017-06-14T02:43:01+00:00","article_modified_time":"2022-01-10T14:48:32+00:00","twitter_card":"summary","twitter_misc":{"Written by":"simplecode","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebSite","@id":"https:\/\/simplecode.com.vn\/#website","url":"https:\/\/simplecode.com.vn\/","name":"SimpleCode","description":"Simple Code","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/simplecode.com.vn\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/simplecode.com.vn\/?p=209#webpage","url":"https:\/\/simplecode.com.vn\/?p=209","name":"Rails API - Quick note - SimpleCode","isPartOf":{"@id":"https:\/\/simplecode.com.vn\/#website"},"datePublished":"2017-06-14T02:43:01+00:00","dateModified":"2022-01-10T14:48:32+00:00","author":{"@id":"https:\/\/simplecode.com.vn\/#\/schema\/person\/b110785905231d29553717dd14b766dc"},"breadcrumb":{"@id":"https:\/\/simplecode.com.vn\/?p=209#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/simplecode.com.vn\/?p=209"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/simplecode.com.vn\/?p=209#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/simplecode.com.vn\/"},{"@type":"ListItem","position":2,"name":"Rails API &#8211; Quick note"}]},{"@type":"Person","@id":"https:\/\/simplecode.com.vn\/#\/schema\/person\/b110785905231d29553717dd14b766dc","name":"simplecode","image":{"@type":"ImageObject","@id":"https:\/\/simplecode.com.vn\/#personlogo","inLanguage":"en-US","url":"https:\/\/secure.gravatar.com\/avatar\/22e0b2cc28939e5aecc166195d629442?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/22e0b2cc28939e5aecc166195d629442?s=96&d=mm&r=g","caption":"simplecode"},"url":"https:\/\/simplecode.com.vn\/?author=1"}]}},"_links":{"self":[{"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=\/wp\/v2\/posts\/209"}],"collection":[{"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=209"}],"version-history":[{"count":14,"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=\/wp\/v2\/posts\/209\/revisions"}],"predecessor-version":[{"id":265,"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=\/wp\/v2\/posts\/209\/revisions\/265"}],"wp:attachment":[{"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=209"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=209"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/simplecode.com.vn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=209"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}