SlideShare a Scribd company logo
1
Augmenting
a legacy {REST} API
with GraphQL
● Started in 2015
● Back end with Ruby on Rails, two mobiles app (Android
and iOS), website
● Good tests coverage but not perfect
● Some functional documentation for critical features
(like payment)
● Small evolutions and dependencies upgrade during the
years
● End of 2019 new big feature: Beehive for Business
Fast and independent
Coworking with self check-in
2
Why did we add
GraphQL ?
1
Specification Development Code is deployed
reviewed
Front-end validates Development
reviewed
New field
is deployed
Front-end needs
a new field
5
Performance
can be an issue
Some fields are
not required
Many endpoints &
representations
of a resource
Some fields are
expensive to
compute
Documentation
By adding tests and using
json-schemas we can make sure
our documentation is up to date
��♂
Data fetching
��♂
Better
performance
��
No graphQL expert
inside our team
Big investmentLearning curve
��
How did we add
GraphQL ?
2
Ask front end if they can use GraphQL API
Start with queries
Added-value is here, we can do mutation later
Write tests if missing
Extract business code from controller into interactor
Write the GraphQL query and types
With an interactor
Extract business code from controller
def index
offers = Offer.all
filtered_offers = offers.available.not_hidden.not_meeting_room
scoped_offers = policy_scope(filtered_offers)
render json: scoped_offers, root: 'offers', serializer: OfferSerializer
end
def index
offers = GetOffers.new.call(current_user: current_user).value!
render json: offers, root: 'offers', serializer: OfferSerializer
end
Query is the entry point
class QueryType < Types::BaseObject
# Add root-level fields here.
# They will be entry points for queries on your schema.
field :offers, [Types::OfferType], null: false
def offers
GetOffers.new.call(
current_user: context[:current_user]
).value!
end
end
Query
FIELDS
offers [Offer!]!
Type is the equivalent of a REST serializer
class OfferType < Types::BaseObject
field :id, ID, null: false
field :name, String, null: false
field :has_access_to_private_offices, Boolean, null: false
field :hidden, Boolean, null: false
field :highlighted, Boolean, null: false
field :ht_price, String, null: false
field :kind, OfferKind, null: false
field :marketing_name, String, null: true
field :multiplier_for_durations, [GraphQL::Types::JSON], null: false
def multiplier_for_durations
object.possible_multipliers.map do |i|
{
string: I18n.t("offers.period.#{object.period}", count: i),
multiplier: i
}
end
end
end
Offer
FIELDS
hasAccessToPrivateOffices Boolean!
hidden Boolean!
highlighted Boolean!
htPrice String!
id ID!
kind OfferKind!
marketingName String!
multiplierForDurations [JSON!]!
name String!
Ask front end if they can use GraphQL API
Start with queries
Added-value is here, we can do mutation later
Write tests if missing
Extract business code from controller into interactor
Write the GraphQL query and types
Adapt your existing tools
Postman => Altair
Is this over ?
3
15
In the REST world it is solved by adding .preload(:offers)
Enterprise.preload(:offers).all
An innocent query…
# SELECT * FROM enterprises (+ 1 query)
Enterprise.all.each do |enterprise|
# SELECT * FROM offers WHERE enterprise_id = ? (n queries)
enterprise.offers.map(&:id)
end
query {
enterprises {
id
offers {
id
}
}
}
...will result in n + 1 queries being made
Result in bad performance
● Batchloading is a generic lazy batching mechanism
● Idea: Delay evaluation to load data in once
https://github.com/exAspArk/batch-loader & https://github.com/graphql/dataloader
class EnterpriseType < Types::BaseObject
field :offers, [Types::OfferType], null: false
def offers
BatchLoader::GraphQL.for(object).batch do |enterprises, loader|
preloader = ActiveRecord::Associations::Preloader.new
preloader.preload(enterprises, :offers)
enterprises.each do |enterprise|
loader.call(enterprise, enterprise.offers)
end
end
end
end
With a custom helper
GraphQL
class EnterpriseType < Types::BaseObject
preload_field :offers, [Types::OfferType], null: false, associations: :offers
end
{REST}
Enterprise.preload(:offers).all
Front end
point of view
4
React
It’s awesome.
Loading state, pagination, caching,
optimistic UI out of the box.
Mobile apps
Neutral
��♂ ��
Mutations
5
Write missing tests
Extract controller code in independant Interactor
Add mutations
createEnterprise
ARGUMENTS
enterpriseRequest CreateEnterpriseRequest!
SUBTYPES
Failure
SuccessOfEnterprise
TYPE
class CreateEnterpriseMutation < Mutations::BaseMutation
argument :enterprise_request, CreateEnterpriseRequestType,
required: true
type failure_union(EnterpriseType)
def resolve(enterprise_request:)
result = CreateEnterprise.new.call(
user: context[:current_user],
params: {
enterprise: enterprise_request.to_h,
}
)
if result.success?
{ success: result.value! }
else
result.failure
end
end
end
FailureOrSuccessOfEnterpriseUnion Union
What’s next ?
6
Handle file upload
Monitoring: everything is under /graphql
Demystify graphQL for the rest of the team
Learning curve
is not that high
Incremental approach
is possible
You can use both
27

More Related Content

PDF
apidays LIVE Paris - GraphQL meshes by Jens Neuse
PDF
apidays LIVE Paris - The Rise of GraphQL for database APIs by Karthic Rao
PDF
apidays LIVE Paris - GraphQL: the AppSec perspective by Vladimir de Turckheim
PPTX
apidays LIVE Paris - Bringing Cloud Native to a world of SaaS by Robert Wunde...
PDF
apidays LIVE Paris - Automation API Testing by Guillaume Jeannic
PDF
Api clarity webinar
PPTX
apidays LIVE Paris - SDK driven GraphQL by Nader Dabit
PDF
apidays LIVE Paris 2021 - Building an analytics API by David Wobrock, Botify
apidays LIVE Paris - GraphQL meshes by Jens Neuse
apidays LIVE Paris - The Rise of GraphQL for database APIs by Karthic Rao
apidays LIVE Paris - GraphQL: the AppSec perspective by Vladimir de Turckheim
apidays LIVE Paris - Bringing Cloud Native to a world of SaaS by Robert Wunde...
apidays LIVE Paris - Automation API Testing by Guillaume Jeannic
Api clarity webinar
apidays LIVE Paris - SDK driven GraphQL by Nader Dabit
apidays LIVE Paris 2021 - Building an analytics API by David Wobrock, Botify

What's hot (20)

PDF
apidays LIVE Paris 2021 - Spatially enabling Web APIs through OGC Standards ...
PPTX
apidays LIVE Australia 2020 - Have your cake and eat it too: GraphQL? REST? W...
PDF
apidays LIVE Australia 2021 - From apps to APIs: how no-code is transforming ...
PDF
apidays LIVE Paris 2021 - 20 Minutes to Build a Serverless COVID-19 GraphQL A...
PDF
apidays LIVE Jakarta - What will the next generation of API Portals look like...
PDF
apidays LIVE Paris - Data with a mission: a COVID-19 API case study by Matt M...
PPTX
apidays LIVE New York 2021 - Service API design validation by Uchit Vyas, KPMG
PPTX
Pain Points In API Development? They’re Everywhere
PDF
apidays LIVE Paris 2021 - What Developers Want by Paul Ardeleanu, Vonage
PDF
Building APIs in a Cloud Native Era
PDF
apidays LIVE Australia 2020 - Federating API Development at Australia’s large...
PPTX
Executing on API Developer Experience
PDF
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
PPTX
Your API Strategy: Why Boring is Best
PDF
apidays LIVE Australia 2021 - Confessions of a Product Geek : My First API BY...
PDF
APIDays - API Design Workshop
PDF
apidays LIVE Paris 2021 - API design is where culture and tech meet each othe...
PDF
apidays LIVE Paris 2021 - Building an Accessible API Spec with Traditional En...
PDF
What do you mean by "API as a Product"?
PDF
apidays LIVE Paris 2021 - Deliver real-time data to customer using Streaming ...
apidays LIVE Paris 2021 - Spatially enabling Web APIs through OGC Standards ...
apidays LIVE Australia 2020 - Have your cake and eat it too: GraphQL? REST? W...
apidays LIVE Australia 2021 - From apps to APIs: how no-code is transforming ...
apidays LIVE Paris 2021 - 20 Minutes to Build a Serverless COVID-19 GraphQL A...
apidays LIVE Jakarta - What will the next generation of API Portals look like...
apidays LIVE Paris - Data with a mission: a COVID-19 API case study by Matt M...
apidays LIVE New York 2021 - Service API design validation by Uchit Vyas, KPMG
Pain Points In API Development? They’re Everywhere
apidays LIVE Paris 2021 - What Developers Want by Paul Ardeleanu, Vonage
Building APIs in a Cloud Native Era
apidays LIVE Australia 2020 - Federating API Development at Australia’s large...
Executing on API Developer Experience
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
Your API Strategy: Why Boring is Best
apidays LIVE Australia 2021 - Confessions of a Product Geek : My First API BY...
APIDays - API Design Workshop
apidays LIVE Paris 2021 - API design is where culture and tech meet each othe...
apidays LIVE Paris 2021 - Building an Accessible API Spec with Traditional En...
What do you mean by "API as a Product"?
apidays LIVE Paris 2021 - Deliver real-time data to customer using Streaming ...
Ad

Similar to apidays LIVE Paris - Augmenting a Legacy REST API with GraphQL by Clément Villain (20)

PDF
GraphQL - when REST API is to less - lessons learned
PDF
GraphQL - when REST API is to less - lessons learned
PDF
How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Pytho...
PDF
GraphQL - when REST API is to less - lessons learned
PDF
GraphQL Bangkok meetup 5.0
PDF
GraphQL - A query language to empower your API consumers (NDC Sydney 2017)
PDF
GraphQL - when REST API is not enough - lessons learned
PPTX
How to provide a GraphQL API - I want it that way
PDF
Graphql
PPTX
Introduction to GraphQL
PDF
GraphQL - when REST API is to less - lessons learned
PDF
Adding GraphQL to your existing architecture
PDF
BruJUG Brussels GraphQL when RESR API is to less - lessons learned
DOCX
GraphQL Advanced Concepts A Comprehensive Guide.docx
PDF
GraphQL across the stack: How everything fits together
PDF
GraphQL - when REST API is to less - lessons learned
PPTX
GraphQL - an elegant weapon... for more civilized age
PDF
GraphQL - when REST API is to less - lessons learned
PDF
apidays LIVE Hong Kong 2021 - GraphQL : Beyond APIs, graph your enterprise by...
PDF
Introduction to GraphQL for beginners
GraphQL - when REST API is to less - lessons learned
GraphQL - when REST API is to less - lessons learned
How to grow GraphQL and remove SQLAlchemy and REST API from a high-load Pytho...
GraphQL - when REST API is to less - lessons learned
GraphQL Bangkok meetup 5.0
GraphQL - A query language to empower your API consumers (NDC Sydney 2017)
GraphQL - when REST API is not enough - lessons learned
How to provide a GraphQL API - I want it that way
Graphql
Introduction to GraphQL
GraphQL - when REST API is to less - lessons learned
Adding GraphQL to your existing architecture
BruJUG Brussels GraphQL when RESR API is to less - lessons learned
GraphQL Advanced Concepts A Comprehensive Guide.docx
GraphQL across the stack: How everything fits together
GraphQL - when REST API is to less - lessons learned
GraphQL - an elegant weapon... for more civilized age
GraphQL - when REST API is to less - lessons learned
apidays LIVE Hong Kong 2021 - GraphQL : Beyond APIs, graph your enterprise by...
Introduction to GraphQL for beginners
Ad

More from apidays (20)

PDF
apidays Munich 2025 - The Physics of Requirement Sciences Through Application...
PDF
apidays Munich 2025 - Developer Portals, API Catalogs, and Marketplaces, Miri...
PDF
apidays Munich 2025 - Making Sense of AI-Ready APIs in a Buzzword World, Andr...
PDF
apidays Munich 2025 - Integrate Your APIs into the New AI Marketplace, Senthi...
PDF
apidays Munich 2025 - The Double Life of the API Product Manager, Emmanuel Pa...
PDF
apidays Munich 2025 - Let’s build, debug and test a magic MCP server in Postm...
PDF
apidays Munich 2025 - The life-changing magic of great API docs, Jens Fischer...
PDF
apidays Munich 2025 - Automating Operations Without Reinventing the Wheel, Ma...
PDF
apidays Munich 2025 - Geospatial Artificial Intelligence (GeoAI) with OGC API...
PPTX
apidays Munich 2025 - GraphQL 101: I won't REST, until you GraphQL, Surbhi Si...
PPTX
apidays Munich 2025 - Effectively incorporating API Security into the overall...
PPTX
apidays Munich 2025 - Federated API Management and Governance, Vince Baker (D...
PPTX
apidays Munich 2025 - Agentic AI: A Friend or Foe?, Merja Kajava (Aavista Oy)
PPTX
apidays Munich 2025 - Streamline & Secure LLM Traffic with APISIX AI Gateway ...
PPTX
apidays Munich 2025 - Building Telco-Aware Apps with Open Gateway APIs, Subhr...
PPTX
apidays Munich 2025 - Building an AWS Serverless Application with Terraform, ...
PDF
apidays Helsinki & North 2025 - REST in Peace? Hunting the Dominant Design fo...
PDF
apidays Helsinki & North 2025 - Monetizing AI APIs: The New API Economy, Alla...
PDF
apidays Helsinki & North 2025 - How (not) to run a Graphql Stewardship Group,...
PDF
apidays Helsinki & North 2025 - APIs in the healthcare sector: hospitals inte...
apidays Munich 2025 - The Physics of Requirement Sciences Through Application...
apidays Munich 2025 - Developer Portals, API Catalogs, and Marketplaces, Miri...
apidays Munich 2025 - Making Sense of AI-Ready APIs in a Buzzword World, Andr...
apidays Munich 2025 - Integrate Your APIs into the New AI Marketplace, Senthi...
apidays Munich 2025 - The Double Life of the API Product Manager, Emmanuel Pa...
apidays Munich 2025 - Let’s build, debug and test a magic MCP server in Postm...
apidays Munich 2025 - The life-changing magic of great API docs, Jens Fischer...
apidays Munich 2025 - Automating Operations Without Reinventing the Wheel, Ma...
apidays Munich 2025 - Geospatial Artificial Intelligence (GeoAI) with OGC API...
apidays Munich 2025 - GraphQL 101: I won't REST, until you GraphQL, Surbhi Si...
apidays Munich 2025 - Effectively incorporating API Security into the overall...
apidays Munich 2025 - Federated API Management and Governance, Vince Baker (D...
apidays Munich 2025 - Agentic AI: A Friend or Foe?, Merja Kajava (Aavista Oy)
apidays Munich 2025 - Streamline & Secure LLM Traffic with APISIX AI Gateway ...
apidays Munich 2025 - Building Telco-Aware Apps with Open Gateway APIs, Subhr...
apidays Munich 2025 - Building an AWS Serverless Application with Terraform, ...
apidays Helsinki & North 2025 - REST in Peace? Hunting the Dominant Design fo...
apidays Helsinki & North 2025 - Monetizing AI APIs: The New API Economy, Alla...
apidays Helsinki & North 2025 - How (not) to run a Graphql Stewardship Group,...
apidays Helsinki & North 2025 - APIs in the healthcare sector: hospitals inte...

Recently uploaded (20)

PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
Approach and Philosophy of On baking technology
PPTX
Programs and apps: productivity, graphics, security and other tools
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Network Security Unit 5.pdf for BCA BBA.
PPTX
1. Introduction to Computer Programming.pptx
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Machine Learning_overview_presentation.pptx
PDF
Machine learning based COVID-19 study performance prediction
PDF
Encapsulation theory and applications.pdf
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Unlocking AI with Model Context Protocol (MCP)
Advanced methodologies resolving dimensionality complications for autism neur...
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
cloud_computing_Infrastucture_as_cloud_p
Approach and Philosophy of On baking technology
Programs and apps: productivity, graphics, security and other tools
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
Network Security Unit 5.pdf for BCA BBA.
1. Introduction to Computer Programming.pptx
NewMind AI Weekly Chronicles - August'25-Week II
Heart disease approach using modified random forest and particle swarm optimi...
Spectral efficient network and resource selection model in 5G networks
Machine Learning_overview_presentation.pptx
Machine learning based COVID-19 study performance prediction
Encapsulation theory and applications.pdf
Univ-Connecticut-ChatGPT-Presentaion.pdf
Digital-Transformation-Roadmap-for-Companies.pptx

apidays LIVE Paris - Augmenting a Legacy REST API with GraphQL by Clément Villain

  • 1. 1 Augmenting a legacy {REST} API with GraphQL
  • 2. ● Started in 2015 ● Back end with Ruby on Rails, two mobiles app (Android and iOS), website ● Good tests coverage but not perfect ● Some functional documentation for critical features (like payment) ● Small evolutions and dependencies upgrade during the years ● End of 2019 new big feature: Beehive for Business Fast and independent Coworking with self check-in 2
  • 3. Why did we add GraphQL ? 1
  • 4. Specification Development Code is deployed reviewed Front-end validates Development reviewed New field is deployed Front-end needs a new field
  • 5. 5 Performance can be an issue Some fields are not required Many endpoints & representations of a resource Some fields are expensive to compute
  • 6. Documentation By adding tests and using json-schemas we can make sure our documentation is up to date ��♂ Data fetching ��♂ Better performance ��
  • 7. No graphQL expert inside our team Big investmentLearning curve ��
  • 8. How did we add GraphQL ? 2
  • 9. Ask front end if they can use GraphQL API Start with queries Added-value is here, we can do mutation later Write tests if missing Extract business code from controller into interactor Write the GraphQL query and types
  • 10. With an interactor Extract business code from controller def index offers = Offer.all filtered_offers = offers.available.not_hidden.not_meeting_room scoped_offers = policy_scope(filtered_offers) render json: scoped_offers, root: 'offers', serializer: OfferSerializer end def index offers = GetOffers.new.call(current_user: current_user).value! render json: offers, root: 'offers', serializer: OfferSerializer end
  • 11. Query is the entry point class QueryType < Types::BaseObject # Add root-level fields here. # They will be entry points for queries on your schema. field :offers, [Types::OfferType], null: false def offers GetOffers.new.call( current_user: context[:current_user] ).value! end end Query FIELDS offers [Offer!]!
  • 12. Type is the equivalent of a REST serializer class OfferType < Types::BaseObject field :id, ID, null: false field :name, String, null: false field :has_access_to_private_offices, Boolean, null: false field :hidden, Boolean, null: false field :highlighted, Boolean, null: false field :ht_price, String, null: false field :kind, OfferKind, null: false field :marketing_name, String, null: true field :multiplier_for_durations, [GraphQL::Types::JSON], null: false def multiplier_for_durations object.possible_multipliers.map do |i| { string: I18n.t("offers.period.#{object.period}", count: i), multiplier: i } end end end Offer FIELDS hasAccessToPrivateOffices Boolean! hidden Boolean! highlighted Boolean! htPrice String! id ID! kind OfferKind! marketingName String! multiplierForDurations [JSON!]! name String!
  • 13. Ask front end if they can use GraphQL API Start with queries Added-value is here, we can do mutation later Write tests if missing Extract business code from controller into interactor Write the GraphQL query and types Adapt your existing tools Postman => Altair
  • 15. 15
  • 16. In the REST world it is solved by adding .preload(:offers) Enterprise.preload(:offers).all An innocent query… # SELECT * FROM enterprises (+ 1 query) Enterprise.all.each do |enterprise| # SELECT * FROM offers WHERE enterprise_id = ? (n queries) enterprise.offers.map(&:id) end query { enterprises { id offers { id } } } ...will result in n + 1 queries being made Result in bad performance
  • 17. ● Batchloading is a generic lazy batching mechanism ● Idea: Delay evaluation to load data in once https://github.com/exAspArk/batch-loader & https://github.com/graphql/dataloader class EnterpriseType < Types::BaseObject field :offers, [Types::OfferType], null: false def offers BatchLoader::GraphQL.for(object).batch do |enterprises, loader| preloader = ActiveRecord::Associations::Preloader.new preloader.preload(enterprises, :offers) enterprises.each do |enterprise| loader.call(enterprise, enterprise.offers) end end end end
  • 18. With a custom helper GraphQL class EnterpriseType < Types::BaseObject preload_field :offers, [Types::OfferType], null: false, associations: :offers end {REST} Enterprise.preload(:offers).all
  • 20. React It’s awesome. Loading state, pagination, caching, optimistic UI out of the box. Mobile apps Neutral ��♂ ��
  • 22. Write missing tests Extract controller code in independant Interactor Add mutations
  • 23. createEnterprise ARGUMENTS enterpriseRequest CreateEnterpriseRequest! SUBTYPES Failure SuccessOfEnterprise TYPE class CreateEnterpriseMutation < Mutations::BaseMutation argument :enterprise_request, CreateEnterpriseRequestType, required: true type failure_union(EnterpriseType) def resolve(enterprise_request:) result = CreateEnterprise.new.call( user: context[:current_user], params: { enterprise: enterprise_request.to_h, } ) if result.success? { success: result.value! } else result.failure end end end FailureOrSuccessOfEnterpriseUnion Union
  • 25. Handle file upload Monitoring: everything is under /graphql Demystify graphQL for the rest of the team
  • 26. Learning curve is not that high Incremental approach is possible You can use both
  • 27. 27