window.pipedriveLeadboosterConfig = { base: pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster on jo olemassa') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Alaresurssien sisällyttäminen REST-mäiseen API:han - The Codest
Codest
  • Tietoa meistä
  • Palvelut
    • Ohjelmistokehitys
      • Frontend-kehitys
      • Backend-kehitys
    • Staff Augmentation
      • Frontend-kehittäjät
      • Backend-kehittäjät
      • Tietoinsinöörit
      • Pilvi-insinöörit
      • QA insinöörit
      • Muut
    • Se neuvoa-antava
      • Tilintarkastus & konsultointi
  • Toimialat
    • Fintech & pankkitoiminta
    • E-commerce
    • Adtech
    • Terveysteknologia
    • Valmistus
    • Logistiikka
    • Autoteollisuus
    • IOT
  • Arvo
    • TOIMITUSJOHTAJA
    • CTO
    • Toimituspäällikkö
  • Tiimimme
  • Tapaustutkimukset
  • Tiedä miten
    • Blogi
    • Tapaamiset
    • Webinaarit
    • Resurssit
Työurat Ota yhteyttä
  • Tietoa meistä
  • Palvelut
    • Ohjelmistokehitys
      • Frontend-kehitys
      • Backend-kehitys
    • Staff Augmentation
      • Frontend-kehittäjät
      • Backend-kehittäjät
      • Tietoinsinöörit
      • Pilvi-insinöörit
      • QA insinöörit
      • Muut
    • Se neuvoa-antava
      • Tilintarkastus & konsultointi
  • Arvo
    • TOIMITUSJOHTAJA
    • CTO
    • Toimituspäällikkö
  • Tiimimme
  • Tapaustutkimukset
  • Tiedä miten
    • Blogi
    • Tapaamiset
    • Webinaarit
    • Resurssit
Työurat Ota yhteyttä
Takaisin nuoli PALAA TAAKSE
2022-03-22
Ohjelmistokehitys

Alaresurssien sisällyttäminen REST-käyttöliittymään

Codest

Krzysztof Buszewicz

Vanhempi Software Engineer

Rakennamme kirjahylly-sovelluksen, jossa luetellaan kirjoja kirjailijatietojen kanssa (tai ilman niitä).

Mitä me teemme?

Rakennamme kirjahylly-sovelluksen, jossa luetellaan kirjoja kirjailijatietojen kanssa (tai ilman niitä). Käytössä on yksi #index toimintaa ja joitakin siemeniä. Tämä on esimerkkisovellus, joka näyttää, miten voit antaa käyttäjälle hallinnan sisällytetyistä alaresurssit REST-käyttöliittymässä (REST-ish API).

"Hyväksymiskriteerit"

  • Käyttäjä voi luetella kirjoja.
  • Käyttäjä voi siirtää sisältää kyselyparametri, jolla ladataan siihen liittyviä resursseja (kirjoittaja).
  • sisältää kyselyparametrin muoto on merkkijono: pilkulla erotetut sanat, jotka edustavat sisäkkäisiä resursseja.
  • Meillä pitäisi olla joitakin vakioita, jotka määrittelevät, mitkä resurssit voidaan sisällyttää mihinkin toimintoon.

Työkalut

Käytämme sinipainaja sarjallistajana, koska se on formaatista riippumaton ja melko joustava. Tämä on ainoa helmi, jonka lisäämme railsin vakiotyökalupakettiin.

Sovellus

Luodaan esimerkkisovellus. Emme lisää testikehystä, koska se ei kuulu tehtäväkenttäämme.

kiskot uusi kirjahylly -T

Luo nyt Kirjoittaja malli:

rails g malli tekijän nimi:string
#=> invoke active_record
#=> create db/migrate/20211224084524_create_authors.rb
#=> luo app/models/author.rb

Ja Kirja:

rails g malli kirja tekijä:viitteet otsikko:merkkijono
# => invoke active_record
# => luo db/migrate/20211224084614_create_books.rb
# => luo app/models/book.rb

Tarvitsemme siemeniä:

# db/seeds.rb

dumas = Author.create(nimi: 'Alexandre Dumas')
lewis = Author.create(name: 'C.S. Lewis')
martin = Author.create(nimi: 'Robert C. Martin')

Book.create(author: dumas, title: 'Kolme muskettisoturia')
Book.create(author: lewis, title: 'Leijona, noita ja vaatekaappi')
Book.create(author: martin, title: 'Clean Code')

Nyt olemme valmiita suorittamaan migraatiot ja kylvämään tietokannan:

rails db:migrate && rails db:seed

Lisätään has_many kirjoja varten Kirjoittaja malli:

# app/models/author.rb

class Author < ApplicationRecord
  has_many :books
end

On aika kirjoittaa ohjain, joka palauttaa tietomme. Käytämme API nimiavaruuteen, joten lisätään ensin lyhenne taivutuksille:

# config/initializers/initializers/inflections.rb

ActiveSupport::Inflector.inflections(:fi) do |inflect|
  inflect.acronym 'API'
end

Okei, lisätään sarjallistajamme tiedostoon Gemfile:

# Lisää Gemfileen

gem 'blueprinter'

Ja tietysti asenna se:

nipun asennus

Sitten voimme rakentaa suunnitelmamme:

# app/blueprints/author_blueprint.rb

class AuthorBlueprint < Blueprinter::Base
  identifier :id

  kentät :name
end
# app/blueprints/book_blueprint.rb

class BookBlueprint < Blueprinter::Base
  identifier :id

  kentät :title

  association :author, blueprint: AuthorBlueprint
end

Lisää perusohjain API:

# app/controllers/api/v1/base_controller.rb

moduuli API
  moduuli V1
    class BaseController < ActionController::API
    end
  end
end

Ja luonnosversio meidän BooksController:

# app/controllers/api/v1/books_controller.rb

moduuli API
  moduuli V1
    class KirjatController < BaseController
      def index
        books = Book.all

        render json: json: BookBlueprint.render(books)
      end
    end
  end
end

Meidän on tietenkin myös määriteltävä reititys:

# config/routes.rb

Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :books, only: :index
    end
  end
end

Testataan, mitä olemme tehneet tähän mennessä:

kiskot s 
curl http://localhost:3000/api/v1/books

# => [{"id":1, "author":{"id":1, "name": "Alexandre Dumas"}, "title": "Kolme muskettisoturia"},{"id":2, "author":{"id":2, "name": "C.S. Lewis"}, "nimi": "Leijona, noita ja vaatekaappi"},{"id":3, "kirjailija":{"id":3, "nimi": "Robert C. Martin"}, "nimi": "Puhdasta Koodi"}]

Tiedot näyttävät olevan kunnossa, entä lokit?

#-pyyntölokit (n+1)

Käynnistetty GET "/api/v1/books" osoitteessa 127.0.0.1 klo 2021-12-24 10:19:40 +0100
Käsittelee API::V1::BooksController#index as */*
  Kirjojen lataus (0.1ms) SELECT "books".* FROM "books" (kirjat)
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Kirjailijoiden lataus (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" = ? LIMIT ?  [[["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Kirjailijoiden lataus (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" = ? LIMIT ?  [[["id", 2], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Kirjailijan lataus (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Suoritettu 200 OK 6ms:ssa (Views: 0.1ms | ActiveRecord: 0.4ms | Allocations: 3134).

Käyttämällä assosiointia sarjallistajissamme otimme käyttöön n+1 ongelma. Haluamme poistaa sen lisäämällä käyttäjälle kontrollin siitä, mitä hän pyytää tässä päätepisteessä. Hänen pitäisi siis pystyä joko lataamaan vain kirjoja tai syöttämään includes-parametri ja saamaan myös kirjailijat, mutta mieluiten ilman includes-parametria. n+1.

Määritellään vakio, joka pitää tietoa siitä, mitä kirjojen assokseja käyttäjä voi sisällyttää tiedostoon books#index toiminta:

# lib/constants/books/includes.rb

moduuli Vakiot
  moduuli Kirjat
    moduuli Includes
      ALLOWED = {
        index: %i[
          kirjoittaja
        ].freeze
      }.freeze
    end
  end
end

Seuraavaksi määrittelemme nimiavaruuden tyhjille objektivakioille:

# lib/constants/empty.rb

moduuli Vakiot
  moduuli Tyhjä
    HASH = {}.freeze
  end
end

Ja tässä on tärkein palvelumme lupien myöntämiseen sisältää. Luulen, että koodi on melko itsestään selvä, joitakin osia magic jaetaan vain #default_resources_key (#default_resources_key) ja #default_purpose. Nämä metodit on määritelty, jotta voimme kutsua permit includes -metodeja välittämällä vain parametrit railsin ohjaimissa. Tuloksena on hash, joka tallentaa true kunkin sallitun sisällyttämisen osalta.

# app/services/permit_includes.rb

require 'constants/empty'
require 'constants/books/includes'

luokka PermitIncludes
  Empty = Constants::Empty

  COMMA = ','
  SLASH = '/'

  INCLUDES_FORMAT = /A[a-z]+(,[a-z]+)*z/.freeze
  ALLOWED_INCLUDES = {
    books: Constants::Books::Includes::ALLOWED
  }.freeze

  def call(params, resources: default_resources_key(params), purpose: default_purpose(params))
    return Empty::HASH ellei includes_sent?(params)
    return Empty::HASH ellei includes_valid?(params)

    requested_includes = parse_includes(params)
    allowed_includes = filter_includes(requested_includes, resources, purpose)

    allowed_includes.index_with(true)
  end

  private

  def default_resources_key(params)
    raise(ArgumentError, 'params :controller key must be a string') unless params[:controller].is_a?(String)

    params[:controller].split(SLASH).last&.to_sym
  end

  def default_purpose(params)
    raise(ArgumentError, 'params :action key must be a string') unless params[:action].is_a?(String)

    params[:action].to_sym
  end

  def includes_sent?(params)
    params.key?(:includes)
  end

  def includes_valid?(params)
    return false unless params[:includes].is_a?(String)

    params[:includes].match?(INCLUDES_FORMAT)
  end

  def parse_includes(params)
    params[:includes].split(COMMA).map(&:to_sym)
  end

  def filter_includes(requested_includes, resources_key, purpose)
    requested_includes & ALLOWED_INCLUDES[resources_key][purpose]
  end
end

Nyt meidän on käytettävä avaimia sisällyttöjen lataamiseen ja välitettävä itse sisällyttöjen hash serializerille:

# app/controllers/api/v1/books_controller.rb

moduuli API
  moduuli V1
    class KirjatController < BaseController
      def index
        includes = PermitIncludes.new.call(params)
        books = Book.includes(includes.keys).all

        render json: BookBlueprint.render(books, includes: includes)
      end
    end
  end
end

Ja näin meidän on säädettävä sarjallistajamme - lataamme assosiaation vain, jos se on mukana:

# app/blueprints/book_blueprint.rb
class BookBlueprint (_field_name, _book, options) {
                         options[:includes] && options[:includes][:author]
                       }
end

Testataan sitä uudelleen:

kiskot s
curl http://localhost:3000/api/v1/books
# => [{"id":1, "title": "Kolme muskettisoturia"},{"id":2, "title": "Leijona, noita ja vaatekaappi"},{"id":3, "title": "Clean Code"}]
#-pyyntölokit (lataamme vain kirjoja)
Käynnistetty GET "/api/v1/books" for ::1 at 2021-12-24 10:33:41 +0100
Käsittelee API::V1::BooksController#index as */*
   (0.1ms) SELECT sqlite_version(*)
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
  Kirjojen lataus (0.1ms) SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Suoritettu 200 OK 9ms:ssa (Views: 0.1ms | ActiveRecord: 0.9ms | Allocations: 4548)

Hyvä, me emme ole läpäisseet sisällyttämistä, joten saimme vain kirjoja, ilman kirjailijoita. Pyydetään nyt niitä:

curl 'http://localhost:3000/api/v1/books?includes=author'
# => [{"id":1, "author":{"id":1, "name": "Alexandre Dumas"}, "title": "Kolme muskettisoturia"},{"id":2, "author":{"id":2, "name": "C.S. Lewis"}, "nimi": "Leijona, noita ja vaatekaappi"},{"id":3, "kirjailija":{"id":3, "nimi": "Robert C. Martin"}, "nimi": "Clean Code"}]% 
#-pyyntöjen lokit (poistettu n+1)

Käynnistetty GET "/api/v1/books?includes=author" for ::1 at 2021-12-24 10:38:23 +0100
Käsittelee API::V1::BooksController#index as */*
  Parametrit: {"includes"=>"author"}
  Kirjan lataus (0.1ms) SELECT "books".* FROM "books" (kirjat)
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
  Kirjailijoiden lataus (0.2ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" IN (?, ?, ?) [["id", 1], ["id", 2], ["id", 3]]
  ↳ app/controllers/api/v1/books_controller.rb:8:in `indeksi'
Suoritettu 200 OK 17ms:ssa (Views: 0.1ms | ActiveRecord: 0.7ms | Allocations: 7373).

Siistiä! Saimme yhdistyksen ladattua ja eliminoitu n+1 ongelma. Palvelua voidaan käyttää mille tahansa resurssille, haluamme vain lisätä sallitut vakiot oikeassa muodossa ja lisätä ne osoitteeseen PermitIncludes::ALLOWED_INCLUDES.

Meidän on muistettava, että tätä pitäisi luultavasti käyttää sivumäärittelyn (ja varovaisuuden) kanssa, koska assosiaatioiden sisällyttäminen voi "syödä" paljon muistia.

Aiheeseen liittyvät artikkelit

Fintech

5 esimerkkiä Rubyn parhaasta käytöstä

Oletko koskaan miettinyt, mitä voimme tehdä Rubylla? No, taivas on luultavasti rajana, mutta puhumme mielellämme muutamista enemmän tai vähemmän tunnetuista tapauksista....

Codest
Pawel Muszynski Software Engineer
Ohjelmistokehitys

Polymorfismi Rubyssä ja GraphQL:ssä

Tässä artikkelissa esittelen polymorfismin käyttöä GraphQL:ssä. Ennen kuin aloitan, on kuitenkin syytä palauttaa mieleen, mitä polymorfismi ja GraphQL ovat.

Lukasz Brzeszcz
E-commerce

Kyberturvallisuuden ongelmat: Tietovuodot

Joulua edeltävä kiire on täydessä vauhdissa. Ihmiset etsivät lahjoja läheisilleen ja ovat yhä useammin valmiita "ryntäämään" verkkokauppoihin.

Codest
Jakub Jakubowicz teknologiajohtaja ja toinen perustaja
Ohjelmistokehitys

Yksinkertainen Ruby-sovellus tyhjästä Active Recordilla

MVC on suunnittelumalli, joka jakaa sovelluksen vastuualueet niin, että sovelluksessa on helpompi liikkua. Rails noudattaa tätä suunnittelumallia sopimuksen mukaan.

Codest
Damian Watroba Software Engineer

Tilaa tietopankkimme ja pysy ajan tasalla IT-alan asiantuntemuksesta.

    Tietoa meistä

    The Codest - Kansainvälinen ohjelmistokehitysyritys, jolla on teknologiakeskuksia Puolassa.

    Yhdistynyt kuningaskunta - pääkonttori

    • Toimisto 303B, 182-184 High Street North E6 2JA
      Lontoo, Englanti

    Puola - Paikalliset teknologiakeskukset

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Krakova
    • Brain Embassy, Konstruktorska
      11, 02-673 Varsova, Puola

      Codest

    • Etusivu
    • Tietoa meistä
    • Palvelut
    • Tapaustutkimukset
    • Tiedä miten
    • Työurat
    • Sanakirja

      Palvelut

    • Se neuvoa-antava
    • Ohjelmistokehitys
    • Backend-kehitys
    • Frontend-kehitys
    • Staff Augmentation
    • Backend-kehittäjät
    • Pilvi-insinöörit
    • Tietoinsinöörit
    • Muut
    • QA insinöörit

      Resurssit

    • Faktoja ja myyttejä yhteistyöstä ulkoisen ohjelmistokehityskumppanin kanssa
    • Yhdysvalloista Eurooppaan: Miksi amerikkalaiset startup-yritykset päättävät muuttaa Eurooppaan?
    • Tech Offshore -kehityskeskusten vertailu: Tech Offshore Eurooppa (Puola), ASEAN (Filippiinit), Euraasia (Turkki).
    • Mitkä ovat teknologiajohtajien ja tietohallintojohtajien tärkeimmät haasteet?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Verkkosivuston käyttöehdot

    Tekijänoikeus © 2025 by The Codest. Kaikki oikeudet pidätetään.

    fiFinnish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek fiFinnish