(function(w,d,s,l,i){w[l]=w[l]|||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=? 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-5LHNRP9'); Apakšresursu iekļaušana REST tipa API - The Codest
The Codest
  • Par mums
  • Pakalpojumi
    • Programmatūras izstrāde
      • Frontend izveide
      • Backend izstrāde
    • Staff Augmentation
      • Frontend izstrādātāji
      • Backend izstrādātāji
      • Datu inženieri
      • Mākoņa inženieri
      • QA inženieri
      • Citi
    • Tā Konsultatīvais dienests
      • Audits un konsultācijas
  • Nozares
    • Fintech un banku darbība
    • E-commerce
    • Adtech
    • Healthtech
    • Ražošana
    • Loģistika
    • Automobiļu nozare
    • IOT
  • Vērtība par
    • CEO
    • CTO
    • Piegādes vadītājs
  • Mūsu komanda
  • Case Studies
  • Zināt, kā
    • Blogs
    • Tikšanās
    • Tiešsaistes semināri
    • Resursi
Karjera Sazinieties ar mums
  • Par mums
  • Pakalpojumi
    • Programmatūras izstrāde
      • Frontend izveide
      • Backend izstrāde
    • Staff Augmentation
      • Frontend izstrādātāji
      • Backend izstrādātāji
      • Datu inženieri
      • Mākoņa inženieri
      • QA inženieri
      • Citi
    • Tā Konsultatīvais dienests
      • Audits un konsultācijas
  • Vērtība par
    • CEO
    • CTO
    • Piegādes vadītājs
  • Mūsu komanda
  • Case Studies
  • Zināt, kā
    • Blogs
    • Tikšanās
    • Tiešsaistes semināri
    • Resursi
Karjera Sazinieties ar mums
Atpakaļ bultiņa ATGRIEZTIES ATPAKAĻ
2022-03-22
Programmatūras izstrāde

Apakšresursu iekļaušana REST tipa API

The Codest

Krzysztof Buszewicz

Vecākais Software Engineer

Mēs izveidosim grāmatu plaukta lietojumprogrammu, lai uzskaitītu grāmatas ar (vai bez) autoru datiem.

Ko mēs darīsim?

Mēs izveidosim grāmatu plaukta lietotni, lai uzskaitītu grāmatas ar (vai bez) autoriem. dati. Būs viens #index darbība un dažas sēklas. Šī būs piemērs, lai parādītu, kā lietotājam var piešķirt kontroli pār iekļautajām programmām. apakšresursus REST-veida API.

“Pieņemšanas kritēriji”

  • Lietotājs var uzskaitīt grāmatas.
  • Lietotājs var nodot ietver vaicājuma parametrs, lai ielādētu saistītos resursus (autors).
  • ietver vaicājuma parametra formāts ir virkne: komatā atdalīti vārdi, kas apzīmē ievietotos resursus.
  • Mums vajadzētu būt konstantām, kas nosaka, kuri resursi ir iekļaujami katrai darbībai.

Instrumenti

Mēs izmantosim blueprinter kā serializatoru, jo tas ir formātneatkarīgs un diezgan elastīgs. Tas ir vienīgais dārgakmens, ko mēs pievienosim rails standarta rīku komplektam.

Lietotne

Izveidosim lietotnes piemēru. Mēs nepievienosim testēšanas ietvaru, jo tas ir ārpus mūsu darbības jomas.

sliedes jauns grāmatu plaukts -T

Tagad izveidojiet Autors modelis:

rails g modeļa autora nosaukums:string
#=> invoke active_record
#=> create db/migrate/2021122224084524_create_authors.rb
#=> create app/models/author.rb

Un Grāmatu:

rails g modelis grāmata autors:references nosaukums:string
# => invoke active_record
# => create db/migrate/2021122224084614_create_books.rb
# => create app/models/book.rb

Mums būs vajadzīgas dažas sēklas:

# db/seeds.rb

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

Book.create(autors: dumas, nosaukums: 'Trīs musketieri')
Book.create(autors: lewis, nosaukums: 'The Lion, the Witch and the Wardrobe')
Book.create(autors: martin, nosaukums: 'Clean Code')

Tagad mēs esam gatavi migrāciju palaišanai un db sēklas izveidei:

rails db:migrate && rails db:seed

Pievienosim has_many par grāmatām Autors modelis:

# app/models/author.rb

klase Author < ApplicationRecord
  has_many :books
end

Ir pienācis laiks uzrakstīt kontrolieri, kas atgriezīs mūsu datus. Mēs izmantosim API vārdu telpa, tāpēc vispirms pievienosim saīsinājumu locījumiem:

# config/initializers/inflections.rb

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

Labi, pievienosim mūsu serializatoru pie Dārgakmens fails:

# Pievienot dārgakmeņu datnei

gem 'blueprinter'

Un, protams, instalējiet to:

instalēt paketi

Tad mēs varam veidot savus plānus:

# app/blueprints/author_blueprint.rb

klase AuthorBlueprint < Blueprinter::Base
  identifier :id

  lauki :name
end
# app/blueprints/book_blueprint.rb

klase BookBlueprint < Blueprinter::Base
  identifikators :id

  lauki :title

  asociācija :author, blueprint: AuthorBlueprint
beigas

Pievienojiet bāzes kontrolieri API:

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

modulis API
  modulis V1
    klase BaseController < ActionController::API
    end
  end
end

Un mūsu BooksController:

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

modulis API
  modulis V1
    klase BooksController < BaseController
      def index
        books = Book.all

        render json: BookBlueprint.render(grāmatas)
      end
    end
  end
end

Protams, mums ir jādefinē arī maršrutēšana:

# config/routes.rb

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

Pārbaudīsim līdz šim paveikto:

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

# => [{"id":1, "author":{"id":1, "name": "Alexandre Dumas"}, "title": "Trīs musketieri"},{"id":2, "author":{"id":2, "name": "C.S. Lewis"}, "title": "The Lion, the Witch and the Wardrobe"},{"id":3, "author":{"id":3, "name": "Robert C. Martin"}, "title": "Clean Kods"}]

Dati, šķiet, ir kārtībā, bet kā ir ar žurnāliem?

# pieprasījumu žurnāli (n+1)

Sākts GET "/api/v1/books" 127.0.0.0.1 2021-12-24 10:19:40 +0100
API::V1::BooksController#index apstrādā kā */*
  Grāmatu ielāde (0.1ms) SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Autoru ielāde (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" = ? LIMIT ?  [[["id", 1], ["LIMIT", 1]]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `in index'
  Autoru ielāde (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" = ? LIMIT ?  [[["id", 2], ["LIMIT", 1]]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Autoru ielāde (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors". "id" = ? LIMIT ?  [[["id", 3], ["LIMIT", 1]]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Pabeigts 200 OK pēc 6 ms (skatījumi: 0,1 ms | ActiveRecord: 0,4 ms | piešķīrumi: 3134)

Izmantojot asociāciju mūsu serializatoros, mēs ieviesām n+1 problēma. Mēs vēlamies to novērst, pievienojot lietotājam kontroli pār to, ko viņš pieprasa šajā galapunktā. Tātad viņam vajadzētu būt iespējai ielādēt tikai grāmatas vai arī nodot parametru includes un saņemt arī autorus, bet vēlams bez parametra n+1.

Definēsim konstanti, kas saglabās informāciju par to, kādus grāmatu asociāciju lietotājs var iekļaut grāmatas#index rīcība:

# lib/constants/books/includes.rb

modulis Constants
  modulis Books
    modulis Includes
      ALLOWED = {
        index: %i[
          autors
        ].freeze
      }.freeze
    beigas
  beigas
end

Tālāk mēs definējam nosaukumu telpu tukšo objektu konstantēm:

# lib/constants/empty.rb

modulis Constants
  modulis Empty
    HASH = {}.freeze
  beigas
beigas

Un šeit ir mūsu galvenais pakalpojums atļauju izsniegšanai. Es domāju, ka kods ir diezgan pašsaprotams, dažas daļas burvju tiek piešķirti tikai #default_resources_key un #default_purpose. Šīs metodes ir definētas, lai mums lai izsauktu atļauju, ietver tikai parametru nodošanu rails’ kontrolieri. Izvades rezultāts būs hash, kas glabā patiess par katru atļauto iekļaušanu.

# app/services/permit_includes.rb

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

klase PermitIncludes
  Empty = Constants::Empty

  COMMA = ','
  SLASH = '/'

  INCLUDES_FORMAT = /A[a-z]+(,[a-z]+)*z/.freeze
  PERMITTED_INCLUDES = {
    grāmatas: Constants::Books::Includes::ALLOWED
  }.freeze

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

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

    allowed_includes.index_with(true)
  beigas

  privāts

  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, ja vien 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

Tagad mums ir nepieciešams izmantot atslēgas, lai ielādētu iekļauj un nodot inlcudes hash pati serializer:

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

modulis API
  modulis V1
    klase BooksController < BaseController
      def index
        includes = PermitIncludes.new.call(params)
        books = Book.includes(includes.keys).all

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

Un tas ir tas, kā mums ir jāpielāgo mūsu serializators - mēs ielādējam asociāciju tikai tad, ja tā ir iekļauta:

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

Pārbaudīsim to vēlreiz:

sliedes s
curl http://localhost:3000/api/v1/books
# => [{"id":1, "title": "Trīs musketieri"},{"id":2, "title": "Lauva, ragana un drēbju skapis"},{"id":3, "title": "Tīrs kods"}]
# pieprasījumu žurnāli (mēs ielādējam tikai grāmatas)
Sākts GET "/api/v1/books" ::1 2021-12-24 10:33:41 +0100
Apstrādā API::V1::BooksController#index kā */*
   (0.1ms) SELECT sqlite_version(*)
  ↳ app/controllers/api/v1/books_controller.rb:8:in `in index'
  Grāmatu ielāde (0.1ms) SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:8:in `in `dex'
Izpildīts 200 OK pēc 9ms (skatījumi: 0,1ms | ActiveRecord: 0,9ms | piešķīrumi: 4548)

Labi, mēs neesam nodevuši ietver, tāpēc saņēmām tikai grāmatas, bez autoriem. Tagad pieprasīsim tos:

curl 'http://localhost:3000/api/v1/books?includes=author'
# => [{"id":1, "author":{"id":1, "name": "Alexandre Dumas"}, "title": "Trīs musketieri"},{"id":2, "author":{"id":2, "name": "C.S. Lewis"}, "title": "The Lion, the Witch and the Wardrobe"},{"id":3, "author":{"id":3, "name": "Robert C. Martin"}, "title": "Clean Code"}]% 
# pieprasījumu žurnāli (novērsts n+1)

Sākts GET "/api/v1/books?includes=author" attiecībā uz ::1 2021-12-24 10:38:23 +0100
Apstrādā API::V1::BooksController#index kā */*
  Parametri: {"includes"=>"author"}
  Grāmatu ielāde (0.1ms) SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:8:in `in index'
  Autoru ielāde (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 `in index'
Pabeigts 200 OK pēc 17 ms (skatījumi: 0,1 ms | ActiveRecord: 0,7 ms | piešķīrumi: 7373)

Forši! Mēs saņēmām asociācija ielādēts un novērsta n+1 problēma. Pakalpojumu var izmantot jebkuram resursam, viss, ko mēs vēlamies darīt, ir pievienot atļautās konstantes pareizā formātā un pievienot tās pie PermitIncludes::ALLOWED_INCLUDES.

Jāatceras, ka tas, iespējams, ir jāizmanto kopā ar pagination (un piesardzīgi), jo asociāciju iekļaušana var “apēst” daudz atmiņas.

Saistītie raksti

Programmatūras izstrāde

5 Ruby labākā lietojuma piemēri

Vai esat kādreiz aizdomājušies, ko mēs varam darīt ar Ruby? Iespējams, debesis ir neierobežotas, taču mēs labprāt pastāstīsim par dažiem vairāk vai mazāk zināmiem gadījumiem...

The Codest
Pawel Muszynski Software Engineer
Programmatūras izstrāde

Polimorfisms Ruby un GraphQL valodās

Šajā rakstā es iepazīstināšu ar polimorfisma izmantošanu GraphQL. Tomēr, pirms es sāku, ir vērts atgādināt, kas ir polimorfisms un GraphQL.

Lukasz Brzeszcz
Programmatūras izstrāde

Kiberdrošības dilemmas: Datu noplūde

Pirmssvētku steiga ir pilnā sparā. Meklējot dāvanas saviem mīļajiem, cilvēki arvien biežāk ir gatavi "šturmēt" interneta veikalus.

The Codest
Jakub Jakubowicz CTO un līdzdibinātājs
Programmatūras izstrāde

Vienkārša Ruby lietojumprogramma no nulles ar Active Record

MVC ir projektēšanas modelis, kas sadala lietojumprogrammas pienākumus, lai atvieglotu tās pārvietošanu. Rails konvencionāli izmanto šo projektēšanas modeli.

The Codest
Damians Watroba Software Engineer

Abonējiet mūsu zināšanu bāzi un saņemiet jaunāko informāciju par IT nozares pieredzi.

    Par mums

    The Codest - starptautisks programmatūras izstrādes uzņēmums ar tehnoloģiju centriem Polijā.

    Apvienotā Karaliste - Galvenā mītne

    • 303B birojs, 182-184 High Street North E6 2JA
      Londona, Anglija

    Polija - Vietējie tehnoloģiju centri

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Krakova
    • Brain Embassy, Konstruktorska
      11, 02-673 Varšava, Polija

    The Codest

    • Sākums
    • Par mums
    • Pakalpojumi
    • Case Studies
    • Zināt, kā
    • Karjera
    • Vārdnīca

    Pakalpojumi

    • Tā Konsultatīvais dienests
    • Programmatūras izstrāde
    • Backend izstrāde
    • Frontend izveide
    • Staff Augmentation
    • Backend izstrādātāji
    • Mākoņa inženieri
    • Datu inženieri
    • Citi
    • QA inženieri

    Resursi

    • Fakti un mīti par sadarbību ar ārējo programmatūras izstrādes partneri
    • No ASV uz Eiropu: Kāpēc Amerikas jaunuzņēmumi nolemj pārcelties uz Eiropu?
    • Tehnoloģiju ārzonas attīstības centru salīdzinājums: Tech Offshore Eiropa (Polija), ASEAN (Filipīnas), Eirāzija (Turcija)
    • Kādi ir galvenie CTO un CIO izaicinājumi?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Autortiesības © 2026 The Codest. Visas tiesības aizsargātas.

    lvLatvian
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian es_ESSpanish nl_NLDutch etEstonian elGreek pt_PTPortuguese cs_CZCzech lt_LTLithuanian is_ISIcelandic lvLatvian