Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

John Vester
John Vester

Posted on

     

When It’s Time to Give REST a Rest

Article Image

Through my years of building services, the RESTful API has been my primary go-to. However, even though REST has its merits, that doesn’t mean it’s the best approach for every use case. Over the years, I’ve learned that, occasionally, there might be better alternatives for certain scenarios. Sticking with REST just because I’m passionate about it—when it’s not the right fit—only results in tech debt and a strained relationship with the product owner.

One of the biggest pain points with the RESTful approach is the need to make multiple requests to retrieve all the necessary information for a business decision. 

As an example, let’s assume I want a 360-view of a customer. I would need to make the following requests:

  • GET /customers/{some_token} provides the base customer information

  • GET /addresses/{some_token} supplies a required address

  • GET /contacts/{some_token} returns the contact information

  • GET /credit/{some_token} returns key financial information

While I understand the underlying goal of REST is to keep responses laser-focused for each resource, this scenario makes for more work on the consumer side. Just to populate a user interface that helps an organization make decisions related to future business with the customer, the consumer must make multiple calls 

In this article, I’ll show whyGraphQL is the preferred approach over a RESTful API here, demonstrating how to deploy Apollo Server (and Apollo Explorer) to get up and running quickly with GraphQL.

I plan to build my solution with Node.js and deploy my solution to Heroku.

When to use GraphQL over REST

There are several common use cases when GraphQL is a better approach than REST:

  • When you needflexibility in how you retrieve data: You can fetch complex data from various resources but all in asingle request. (I will dive down this path in this article.)

  • When the frontend team needs toevolve the UI frequently: Rapidly changingdata requirements won’t require the backend to adjust endpoints and cause blockers.

  • When you want tominimize over-fetching andunder-fetching: Sometimes REST requires you to hit multiple endpoints to gather all the data you need (under-fetching), or hitting a single endpoint returns way more data than you actually need (over-fetching).

  • When you’re working with complex systems and microservices: Sometimesmultiple sources just need to hit a single API layer for their data. GraphQL can provide that flexibility through asingle API call.

  • When you need real-time data pushed to you: GraphQL featuressubscriptions, which provide real-time updates. This is useful in the case of chat apps or live data feeds. (I will cover this benefit in more detail in a follow-up article.)

What is Apollo Server?

Since my skills with GraphQL aren’t polished, I decided to go withApollo Server for this article.

Apollo Server is a GraphQL server that works with any GraphQL schema. The goal is to simplify the process of building a GraphQL API. The underlying design integrates well with frameworks such as Express or Koa. I will explore the ability to leverage subscriptions (via thegraphql-ws library) for real-time data in my next article.

Where Apollo Server really shines is the Apollo Explorer, a built-in web interface that developers can use to explore and test their GraphQL APIs. The studio will be a perfect fit for me, as it allows for the easy construction of queries and the ability to view the API schema in a graphical format.

My Customer 360 Use Case

For this example, let’s assume we need the following schema to provide a 360-view of the customer:

typeCustomer{token:Stringname:Stringsic_code:String}typeAddress{token:Stringcustomer_token:Stringaddress_line1:Stringaddress_line2:Stringcity:Stringstate:Stringpostal_code:String}typeContact{token:Stringcustomer_token:Stringfirst_name:Stringlast_name:Stringemail:Stringphone:String}typeCredit{token:Stringcustomer_token:Stringcredit_limit:Floatbalance:Floatcredit_score:Int}
Enter fullscreen modeExit fullscreen mode

I plan to focus on the following GraphQL queries:

typeQuery{addresses:[Address]address(customer_token:String):Addresscontacts:[Contact]contact(customer_token:String):Contactcustomers:[Customer]customer(token:String):Customercredits:[Credit]credit(customer_token:String):Credit}
Enter fullscreen modeExit fullscreen mode

Consumers will provide the token for the Customer they wish to view. We expect to also retrieve the appropriate Address, Contact, and Credit objects. The goal is to avoid making four different API calls for all this information rather than with a single API call.

Getting Started with Apollo Server

I started by creating a new folder calledgraphql-server-customer on my local workstation. Then, using theGet Started section of the Apollo Server documentation, I followed steps one and two using a Typescript approach.

Next, I defined my schema and also included some static data for testing. Ordinarily, we would connect to a database, but static data will work fine for this demo.

Below is my updatedindex.ts file:

import{ApolloServer}from'@apollo/server';import{startStandaloneServer}from'@apollo/server/standalone';consttypeDefs=`#graphqltypeCustomer{token:Stringname:Stringsic_code:String}typeAddress{token:Stringcustomer_token:Stringaddress_line1:Stringaddress_line2:Stringcity:Stringstate:Stringpostal_code:String}typeContact{token:Stringcustomer_token:Stringfirst_name:Stringlast_name:Stringemail:Stringphone:String}typeCredit{token:Stringcustomer_token:Stringcredit_limit:Floatbalance:Floatcredit_score:Int}typeQuery{addresses:[Address]address(customer_token:String):Addresscontacts:[Contact]contact(customer_token:String):Contactcustomers:[Customer]customer(token:String):Customercredits:[Credit]credit(customer_token:String):Credit}`;constresolvers={Query:{addresses:()=>addresses,address:(parent,args,context)=>{constcustomer_token=args.customer_token;returnaddresses.find(address=>address.customer_token===customer_token);},contacts:()=>contacts,contact:(parent,args,context)=>{constcustomer_token=args.customer_token;returncontacts.find(contact=>contact.customer_token===customer_token);},customers:()=>customers,customer:(parent,args,context)=>{consttoken=args.token;returncustomers.find(customer=>customer.token===token);},credits:()=>credits,credit:(parent,args,context)=>{constcustomer_token=args.customer_token;returncredits.find(credit=>credit.customer_token===customer_token);}},};constserver=newApolloServer({typeDefs,resolvers,});const{url}=awaitstartStandaloneServer(server,{listen:{port:4000},});console.log(`ApolloServerreadyat:${url}`);constcustomers=[{token:'customer-token-1',name:'AcmeInc.',sic_code:'1234'},{token:'customer-token-2',name:'WidgetCo.',sic_code:'5678'}];constaddresses=[{token:'address-token-1',customer_token:'customer-token-1',address_line1:'123MainSt.',address_line2:'',city:'Anytown',state:'CA',postal_code:'12345'},{token:'address-token-22',customer_token:'customer-token-2',address_line1:'456ElmSt.',address_line2:'',city:'Othertown',state:'NY',postal_code:'67890'}];constcontacts=[{token:'contact-token-1',customer_token:'customer-token-1',first_name:'John',last_name:'Doe',email:'jdoe@example.com',phone:'123-456-7890'}];constcredits=[{token:'credit-token-1',customer_token:'customer-token-1',credit_limit:10000.00,balance:2500.00,credit_score:750}];
Enter fullscreen modeExit fullscreen mode

With everything configured as expected, we run the following command to start the server:

$ npm start
Enter fullscreen modeExit fullscreen mode

With the Apollo server running on port 4000, I used thehttp://localhost:4000/ URL to access Apollo Explorer. Then I set up the following example query:

query ExampleQuery {  addresses {    token  }  contacts {    token  }  customers {    token  }}
Enter fullscreen modeExit fullscreen mode

This is how it looks in Apollo Explorer:

Image #1

Pushing theExample Query button, I validated that the response payload aligned with the static data I provided in theindex.ts:

{"data":{"addresses":[{"token":"address-token-1"},{"token":"address-token-22"}],"contacts":[{"token":"contact-token-1"}],"customers":[{"token":"customer-token-1"},{"token":"customer-token-2"}]}}
Enter fullscreen modeExit fullscreen mode

Before going any further in addressing my Customer 360 use case, I wanted to run this service in the cloud.

Deploying Apollo Server to Heroku

Since this article is all about doing something new, I wanted to see how hard it would be to deploy my Apollo server to Heroku.

I knew I had to address the port number differences between running locally and running somewhere in the cloud. I updated my code for starting the server as shown below:

const{url}=awaitstartStandaloneServer(server,{listen:{port:Number.parseInt(process.env.PORT)||4000},});
Enter fullscreen modeExit fullscreen mode

With this update, we’ll use port 4000 unless there is a PORT value specified in an environment variable.

Using Gitlab, I created a new project for these files and logged into my Heroku account using the Heroku command-line interface (CLI):

$ heroku login
Enter fullscreen modeExit fullscreen mode

You can create a new app in Heroku with either their CLI or the Heroku dashboard web UI. For this article, we’ll use the CLI:

$ heroku create jvc-graphql-server-customer
Enter fullscreen modeExit fullscreen mode

The CLI command returned the following response:

Creating ⬢ jvc-graphql-server-customer... donehttps://jvc-graphql-server-customer-b62b17a2c949.herokuapp.com/ | https://git.heroku.com/jvc-graphql-server-customer.git
Enter fullscreen modeExit fullscreen mode

The command also added the repository used by Heroku as a remote automatically:

$ git remoteherokuorigin
Enter fullscreen modeExit fullscreen mode

By default, Apollo Server disables Apollo Explorer in production environments. For my demo, I want to leave it running on Heroku. To do this, I need to set theNODE_ENV environment variable to development. I can set that with the following CLI command:

$ heroku config:set NODE_ENV=development
Enter fullscreen modeExit fullscreen mode

The CLI command returned the following response:

Setting NODE_ENV and restarting ⬢ jvc-graphql-server-customer... done, v3NODE_ENV: development
Enter fullscreen modeExit fullscreen mode

Now we’re in a position to deploy our code to Heroku:

$ git commit --allow-empty -m 'Deploy to Heroku'$ git push heroku
Enter fullscreen modeExit fullscreen mode

A quick view of the Heroku Dashboard shows my Apollo Server running without any issues:

Image #2

If you’re new to Heroku,this guide will show you how to create a new account and install the Heroku CLI.

Acceptance Criteria Met: My Customer 360 Example

With GraphQL, I can meet the acceptance criteria for my Customer 360 use case with the following query:

queryCustomerData($token:String){customer(token:$token){namesic_codetoken},address(customer_token:$token){tokencustomer_tokenaddress_line1address_line2citystatepostal_code},contact(customer_token:$token){token,customer_token,first_name,last_name,email,phone},credit(customer_token:$token){token,customer_token,credit_limit,balance,credit_score}}
Enter fullscreen modeExit fullscreen mode

All I need to do is pass in a single Customertoken variable with a value ofcustomer-token-1:

{"token":"customer-token-1"}
Enter fullscreen modeExit fullscreen mode

We can retrieve all of the data using a single GraphQL API call:

{"data":{"customer":{"name":"Acme Inc.","sic_code":"1234","token":"customer-token-1"},"address":{"token":"address-token-1","customer_token":"customer-token-1","address_line1":"123 Main St.","address_line2":"","city":"Anytown","state":"CA","postal_code":"12345"},"contact":{"token":"contact-token-1","customer_token":"customer-token-1","first_name":"John","last_name":"Doe","email":"jdoe@example.com","phone":"123-456-7890"},"credit":{"token":"credit-token-1","customer_token":"customer-token-1","credit_limit":10000,"balance":2500,"credit_score":750}}}
Enter fullscreen modeExit fullscreen mode

Below is a screenshot from Apollo Explorer running from my Heroku app:

Image #3

Conclusion

I recall earlier in my career when Java and C# were competing against each other for developer adoption. Advocates on each side of the debate were ready to prove that their chosen tech was the best choice … even when it wasn’t.

In this example, we could have met my Customer 360 use case in multiple ways. Using a proven RESTful API would have worked, but it would have required multiple API calls to retrieve all of the necessary data. Using Apollo Server and GraphQL allowed me to meet my goals with a single API call.

I also love how easy it is to deploy my GraphQL server to Heroku with just a few commands in my terminal. This allows me to focus on implementation—offloading the burdens of infrastructure and running my code to a trusted third-party provider. Most importantly, this falls right in line with my personal mission statement:

“Focus your time on delivering features/functionality that extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.” – J. Vester

If you are interested in the source code for this article, it is available onGitLab.

But wait… there’s more! 

In my follow-up post, we will build out our GraphQL server further, to implement authentication and real-time data retrieval with subscriptions.

Have a really great day!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Information Technology professional with 25+ years expertise in enterprise architecture/application design, application development, project management, system administration and team supervision.
  • Location
    United States
  • Work
    Lead Software Engineer @ Marqeta
  • Joined

More fromJohn Vester

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp