(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'); Innifela undirstakstengi í REST-líkum API - The Codest
The Codest
  • Um okkur
  • Þjónusta
    • Hugbúnaðarþróun
      • Framhliðþróun
      • Bakendaþróun
    • Staff Augmentation
      • Framhliðaráþrófarar
      • Bakhliðaráþróunaraðilar
      • Gagnaverkfræðingar
      • Skýjaverkfræðingar
      • Gæðatryggingartæknimenn
      • Annað
    • Það er ráðgjafi
      • Endurskoðun og ráðgjöf
  • Iðnaðargreinar
    • Fjártæknifyrirtæki og bankastarfsemi
    • E-commerce
    • Adtech
    • Heilbrigðistækni
    • Framleiðsla
    • Flutningar
    • Bifreiða
    • Internet hlutanna
  • Gildi fyrir
    • CEO
    • CTO
    • Afhendingarstjóri
  • Teymið okkar
  • Case Studies
  • Vitið hvernig
    • Blogg
    • Fundir
    • Vefnámskeið
    • Auðlindir
Starfsferilmöguleikar Hafðu samband
  • Um okkur
  • Þjónusta
    • Hugbúnaðarþróun
      • Framhliðþróun
      • Bakendaþróun
    • Staff Augmentation
      • Framhliðaráþrófarar
      • Bakhliðaráþróunaraðilar
      • Gagnaverkfræðingar
      • Skýjaverkfræðingar
      • Gæðatryggingartæknimenn
      • Annað
    • Það er ráðgjafi
      • Endurskoðun og ráðgjöf
  • Gildi fyrir
    • CEO
    • CTO
    • Afhendingarstjóri
  • Teymið okkar
  • Case Studies
  • Vitið hvernig
    • Blogg
    • Fundir
    • Vefnámskeið
    • Auðlindir
Starfsferilmöguleikar Hafðu samband
Aftur ör Farðu aftur
2022-03-22
Hugbúnaðarþróun

Innifela undirstakkar í REST-líkum API

The Codest

Krzysztof Buszewicz

Eldri nemandi Software Engineer

Við munum búa til bókahillu-app sem skráir bækur með (eða án) höfundagagna.

Hér er tómt.

Hvað munum við gera?

Við munum búa til bókahillu-app sem skráir bækur með (eða án) höfunda gögn. Það verður eitt #vísitala aðgerð og nokkur fræ. Þetta verður dæmi um forrit til að sýna hvernig þú getur gefið notanda stjórn á inniföldu undirauðlindir í REST-líkum forritaskil.

“Samþykkiskröfur”

  • Notandi getur skráð bækurnar.
  • Notandi getur sent innifelur Fyrirspurnarparametri til að hlaða tengdum auðlindum (höfundur).
  • innifelur Símtaksparametrinn hefur sniðið streng: kommur aðskilin orð sem tákna innfelldar auðlindir.
  • Við ættum að hafa nokkrar fastastærðir sem skilgreina hvaða auðlindir sé hægt að fella inn fyrir hvaða aðgerð.

Tæki

Við munum nota bláprentari sem serializer, vegna þess að hann er formatiðlaus og nokkuð sveigjanlegur. Þetta er eina gemmið sem við munum bæta við staðlaða verkfærakistu Rails.

Forritið

Búum til dæmisforrit. Við bætum ekki við prófunarramma þar sem það er utan okkar verksviðs.

járnbrautir ný bókaskápur -T

Nú búa til Höfundur líkan:

rails g model author name:string
#=> invoke  active_record
#=> create    db/migrate/20211224084524_create_authors.rb
#=> create    app/models/author.rb

Og Bók:

rails g model book author:references title:string
# => invoke  active_record
# => create    db/migrate/20211224084614_create_books.rb
# => create    app/models/book.rb

Við munum þurfa nokkur fræ:

# 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(author: dumas, title: 'The Three Musketeers')
Book.create(author: lewis, title: 'The Lion, the Witch and the Wardrobe')
Book.create(author: martin, title: 'Clean Code')

Og nú erum við tilbúin að keyra flutninga og fræa gagnagrunninn:

rails db:migrate && rails db:seed

Bætum við á marga fyrir bækur í Höfundur líkan:

# app/models/author.rb

class Author < ApplicationRecord
  has_many :books
end

Það er kominn tími til að skrifa stjórnanda sem skilar gögnum okkar. Við munum nota forritaskil Nafnorðarrými, svo skulum við fyrst bæta skammstöfun við beygingar:

# config/initializers/inflections.rb

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

Ok, skulum bæta við serializerinn okkar við Gems-skrá:

# Bæta við Gemfile

gem 'blueprinter'

Og auðvitað skaltu setja það upp:

Sjálfvirk uppsetning

Þá getum við smíðað uppdrættina okkar:

# app/blueprints/author_blueprint.rb

class AuthorBlueprint < Blueprinter::Base
  identifier :id

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

class BookBlueprint < Blueprinter::Base
  identifier :id

  fields :title

  association :author, blueprint: AuthorBlueprint
end

Bættu við grunnstjóra fyrir forritaskil:

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

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

Og drögin af okkar BókaStýring:

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

module API
  module V1
    class BooksController < BaseController
 def index
 books = Book.all

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

Við verðum einnig að skilgreina leiðarvalið auðvitað:

# config/routes.rb

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

Skoðum hvað við höfum gert hingað til:

járnbrautir s 
curl http://localhost:3000/api/v1/books

# => [{"id":1,"author":{"id":1,"name":"Alexandre Dumas"},"title":"Þrír muskétumennirnir"},{"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 Kóði"}]

Gögnin virðast vera í lagi, hvað með skráningar?

# beiðnisdagbók (n+1)

Byrjað GET "/api/v1/books" fyrir 127.0.0.1 kl. 2021-12-24 10:19:40 +0100
Unnið af API::V1::BooksController#index sem */*
  Bóka hleðsla (0.1ms)  SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Höfundar hleðsla (0.1ms)  SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Höfundur hlaðinn (0,1 ms)  SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
  Hleðsla höfundar (0.1ms)  SELECT "authors".* FROM "authors" WHERE "authors"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
  ↳ app/controllers/api/v1/books_controller.rb:7:in `index'
Completed 200 OK in 6ms (Views: 0.1ms | ActiveRecord: 0.4ms | Allocations: 3134)

Með því að nota tengingu í serializerunum okkar kynntum við n+1 vandamál. Við viljum útrýma því með því að bæta við notanda stjórn á því hvað hann biður um í þessum enda punkti. Svo ætti hann að geta annaðhvort hlaðið eingöngu bækur eða sent includes-breytuna og fengið höfunda líka, en helst án n+1.

Skulum skilgreina fasti sem mun geyma upplýsingar um hvaða tengdar bækur notandi getur bætt við bækur#vísitala aðgerð:

# lib/constants/books/includes.rb

module Constants
  module Books
    module Includes
 ALLOWED = {
 index: %i[
 author
 ].freeze
 }.freeze
    end
  end
end

Næst skilgreinum við nafnarými fyrir tómar hlutastöðugar breytur:

# lib/constants/empty.rb

module Constants
  module Empty
    HASH = {}.freeze
  end
end

Og hér er aðalþjónustan okkar fyrir leyfisveitingar. Ég held að kóðinn sé nokkuð sjálfskýrandi, nokkrir hlutar af galdur eru aðeins úthlutaðar í #gagnaupplýsingalykill_sjálfgefið og #default_purpose. Þessar aðferðir eru skilgreindar til að leyfa okkur Til að kalla leyfi felur í sér að senda eingöngu breytur í Rails-stjórnendum. Úttakið verður hashinn sem geymir sannur fyrir hverja leyfða innlimun.

# app/services/permit_includes.rb

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

class 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 unless includes_sent?(params)
    return Empty::HASH unless 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 lykillinn verður að vera strengur') 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

Nú þurfum við að nota lyklana til að hlaða includes og senda includes-hashinn sjálfan til serializer-sins:

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

module API
  module V1
    class BooksController < 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

Og svona verðum við að fínstilla serializerinn okkar – við hleðjum tenginguna aðeins ef hún er innifalin:

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

Skoðum það aftur:

járnbrautir s
curl http://localhost:3000/api/v1/books
# => [{"id":1,"title":"The Three Musketeers"},{"id":2,"title":"The Lion, the Witch and the Wardrobe"},{"id":3,"title":"Clean Code"}]
# beiðnisdagbækur (við hleðjum aðeins bækur)
Byrjað GET "/api/v1/books" fyrir ::1 kl. 2021-12-24 10:33:41 +0100
Vinnsla með API::V1::BooksController#index sem */*
   (0.1ms)  SELECT sqlite_version(*)
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
  Bók hleðsla (0.1ms)  SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Lokið 200 OK á 9ms (Sýnir: 0.1ms | ActiveRecord: 0.9ms | Úthlutanir: 4548)

Gott, við höfum ekki sent inn `include`-skrána, svo við höfum aðeins bækur án höfunda. Nú skulum við biðja um þær:

curl 'http://localhost:3000/api/v1/books?includes=author'
# => [{"id":1,"author":{"id":1,"name":"Alexandre Dumas"},"title":"Þrír muskétumennirnir"},{"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"}]% 
# beiðnisdagbækur (eytt n+1)

Hóf GET "/api/v1/books?includes=author" fyrir ::1 þann 2021-12-24 10:38:23 +0100
Unnið af API::V1::BooksController#index sem */*
  Breytur: {"includes"=>"author"}
  Bókaslóðun (0.1ms)  SELECT "books".* FROM "books"
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
  Hlaða höfundi (0,2 ms)  SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (?, ?, ?)  [["id", 1], ["id", 2], ["id", 3]]
  ↳ app/controllers/api/v1/books_controller.rb:8:in `index'
Lokið 200 OK á 17ms (Sýnir: 0.1ms | ActiveRecord: 0.7ms | Úthlutanir: 7373)

Frábært! Við fengum samtökin hlaðin og útrýmt. n+1 vandamál. Þjónustan má nota fyrir hvaða auðlind sem er; allt sem við þurfum að gera er að bæta leyfðar includes-fastastærðir í rétt snið og bæta þær við PermitIncludes::ALLOWED_INCLUDES.

Við verðum að muna að þetta ætti líklega að nota með síðaskiptingu (og varúð) vegna þess að innifalið tengsl geta “étið” mikið minni.

Tengdar greinar

Hugbúnaðarþróun

5 dæmi um bestu notkun Ruby

Hefurðu einhvern tíma velt því fyrir þér hvað við getum gert með Ruby? Jæja, loftið er líklega takmörkin, en við erum fús til að segja frá nokkrum meira eða minna þekktum dæmum...

The Codest
Pawel Muszynski Software Engineer
Hugbúnaðarþróun

Polymorphism í Ruby og GraphQL

Í þessari grein mun ég kynna notkun margforms í GraphQL. Áður en ég byrja er þó vert að rifja upp hvað margform og GraphQL eru.

Lukasz Brzeszcz
Hugbúnaðarþróun

Öryggisvandamál á netinu: Gagnaleki

Framundan jólin er í fullum gangi. Í leit að gjöfum fyrir ástvini sína eru menn sífellt reiðubúnari til að “rjúka” inn í netverslanir.

The Codest
Jakub Jakubowicz CTO og meðstofnandi
Hugbúnaðarþróun

Einföld Ruby-forritun frá grunni með Active Record

MVC er hönnunarmynstur sem skiptir ábyrgðum forrits til að auðvelda siglingar. Rails fylgir þessu hönnunarmynstri samkvæmt venju.

The Codest
Damian Watroba Software Engineer

Gerðu þig áskrifanda að þekkingargrunni okkar og vertu upplýstur um sérfræðiþekkingu upplýsingatæknigeirans.

    Um okkur

    The Codest – Alþjóðlegt hugbúnaðarþróunarfyrirtæki með tæknimiðstöðvar í Póllandi.

    Bretland - Höfuðstöðvar

    • Skrifstofa 303B, 182-184 High Street North E6 2JA
      Lundúnir, England

    Pólland - staðbundin tæknimiðstöðvar

    • Fabryczna skrifstofugarður, Aleja
      Herbergi 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Varsjá, Pólland

    The Codest

    • Heim
    • Um okkur
    • Þjónusta
    • Case Studies
    • Vitið hvernig
    • Starfsferilmöguleikar
    • Orðabók

    Þjónusta

    • Það er ráðgjafi
    • Hugbúnaðarþróun
    • Bakendaþróun
    • Framhliðþróun
    • Staff Augmentation
    • Bakhliðaráþróunaraðilar
    • Skýjaverkfræðingar
    • Gagnaverkfræðingar
    • Annað
    • Gæðatryggingartæknimenn

    Auðlindir

    • Staðreyndir og goðsagnir um samstarf við utanaðkomandi hugbúnaðarþróunaraðila
    • Frá Bandaríkjunum til Evrópu: Af hverju ákveða bandarísk sprotafyrirtæki að flytja til Evrópu?
    • Samanburður á tæknifjarkerfisþróunarmiðstöðvum: Tech Offshore Europe (Pólland), ASEAN (Filippseyjar), Eurasia (Tyrkland)
    • Hvert eru helstu áskoranir CTO-a og CIO-a?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Höfundarréttur © 2026 af The Codest. Öll réttindi áskilin.

    is_ISIcelandic
    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 lvLatvian lt_LTLithuanian is_ISIcelandic