# Make a REST API call Once OAuth is complete, we can use `ShopifyAPI`'s REST library to make authenticated API calls to the Shopify Admin API. #### Required Session Every API request requires a valid [ShopifyAPI::Auth::Session](https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/auth/session.rb). To instantiate a session, we recommend you either use the `shopify_app` if working in Rails, or refer to our OAuth docs on constructing a session: - ["Custom Apps"](https://github.com/Shopify/shopify-api-ruby/blob/main/docs/usage/custom_apps.md) - documentation on how to create Session from a custom app API token. - ["Performing OAuth"](https://github.com/Shopify/shopify-api-ruby/blob/main/docs/usage/oauth.md) - documentation on how to create new sessions - [[ShopifyApp] - "Session"](https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/sessions.md) - documentation on session handling if you're using the [`ShopifyApp`](https://github.com/Shopify/shopify_app) gem. #### There are 2 methods you can use to make REST API calls to Shopify: - [Using REST Resources](#using-rest-resources) - Resource classes with similar syntax as `ActiveResource`, and follows our REST convention. Example: ``` ruby # Update product title product = ShopifyAPI::Product.find(id: ) product.title = "My awesome product" product.save! ``` - [Using REST Admin Client](#using-rest-admin-client) - More manual input method to make the API call. Example: ```ruby # Create a new client. rest_client = ShopifyAPI::Clients::Rest::Admin.new # Update product title body = { product: { title: "My cool product" } } # Use `client.put` to send your request to the specified Shopify Admin REST API endpoint. rest_client.put(path: "products/.json", body: body) ``` ## Using REST Resources We provide a templated class library to access REST resources similar to `ActiveResource`. Format of the methods closely resemble our [REST API schema](https://shopify.dev/docs/api/admin-rest). The version of REST resource that's loaded and used is set from [`ShopifyAPI::Context.setup`](https://github.com/Shopify/shopify-api-ruby/blob/main/README.md#setup-shopify-context) ### Instantiation Create an instance of the REST resource you'd like to use and optionally provide the following parameters. #### Constructor parameters | Parameter | Type | Notes | | ----------|------|-------| | `session` | `ShopifyAPI::Auth::Session` | Default value is `nil`.

When `nil` is passed in, active session information is inferred from `ShopifyAPI::Context.active_session`.
To set active session, use `ShopifyAPI::Context.activate_session`.

This is handled automatically behind the scenes if you use ShopifyApp's [session controllers](https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/sessions.md). | | `from_hash` | `Hash` | Default value is `nil`. Sets the resource properties to the values provided from the hash. | Examples: ```ruby # To construct an Orders object using default session # This creates a new order object with properties provided from the hash order = ShopifyAPI::Orders.new(from_hash: {property: value}) order.save! ``` ### Methods Typical methods provided for each resources are: - `find` - `delete` - `all` - `count` Full list of methods can be found on each of the resource class. - Path: - https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/rest/resources/#{version}/#{resource}.rb - Example for `Order` resource on `2024-01` version: - https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/rest/resources/2024_01/order.rb ### The `save` method The `save` or `save!` method on a resource allows you to `create` or `update` that resource. #### Create a new resource To create a new resource using the `save` or `save!` method, you can initialize the resource with a hash of values or simply assigning them manually. For example: ```Ruby # Create a new product from hash product_properties = { title: "My awesome product" } product = ShopifyAPI::Product.new(from_hash: product_properties) product.save! # Create a new product manually product = ShopifyAPI::Product.new product.title = "Another one" product.save! ``` #### Update an existing resource To update an existing resource using the `save` or `save!` method, you'll need to fetch the resource from Shopify first. Then, you can manually assign new values to the resource before calling `save` or `save!`. For example: ```Ruby # Update a product's title product = ShopifyAPI::Product.find(id: product_id) product.title = "My new title" product.save! # Remove a line item from a draft order draft_order = ShopifyAPI::DraftOrder.find(id: draft_order_id) new_line_items = draft_order.line_items.reject { |line_item| line_item["id"] == 12345 } draft_order.line_items = new_line_items draft_order.save! ``` > [!IMPORTANT] > If you need to unset an existing value, > please explicitly set that attribute to `nil` or empty values such as `[]` or `{}`. For example: > > ```Ruby > # Removes shipping address from draft_order > draft_order.shipping_address = {} > draft_order.save! > ``` > > This is because only modified values are sent to the API, so if `shipping_address` is not "modified" to `{}`. It won't be part of the PUT request payload When updating a resource, only the modified attributes, the resource's primary key, and required parameters are sent to the API. The primary key is usually the `id` attribute of the resource, but it can vary if the `primary_key` method is overwritten in the resource's class. The required parameters are identified using the path parameters of the `PUT` endpoint of the resource. ### Headers You can add custom headers to the HTTP calls made by methods like `find`, `delete`, `all`, `count` by setting the `headers` attribute on the `ShopifyAPI::Rest::Base` class in an initializer, like so: ```ruby ShopifyAPI::Rest::Base.headers = { "X-Custom-Header" => "Custom Value" } # `find` will call the API endpoint with the custom header ShopifyAPI::Customer.find(id: customer_id) ``` ### Usage Examples ⚠️ The [API reference documentation](https://shopify.dev/docs/api/admin-rest) contains more examples on how to use each REST Resources. ```Ruby # Find and update a customer email customer = ShopifyAPI::Customer.find(id: customer_id) customer.email = "steve-lastnameson@example.com" customer.save! # Get all orders orders = ShopifyAPI::Orders.all # Retrieve a specific fulfillment order fulfillment_order_id = 123456789 fulfillment_order = ShopifyAPI::FulfillmentOrder.find(id: fulfillment_order_id) # Remove an existing product image product_id = 1234567 image_id = 1233211234567 ShopifyAPI::Image.delete(product_id: product_id, id: image_id) ``` More examples can be found in each resource's documentation on [shopify.dev](https://shopify.dev/docs/api/admin-rest), e.g.: - [Order](https://shopify.dev/docs/api/admin-rest/current/resources/order) - [Product](https://shopify.dev/docs/api/admin-rest/current/resources/product) ## Using REST Admin Client ### Instantiation Create an instance of [`ShopifyAPI::Clients::Rest::Admin`](https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/clients/rest/admin.rb) using the current session to make requests to the Admin API. #### Constructor parameters | Parameter | Type | Notes | | ----------|------|-------| | `session` | `ShopifyAPI::Auth::Session` | Default value is `nil`.

When `nil` is passed in, active session information is inferred from `ShopifyAPI::Context.active_session`.
To set active session, use `ShopifyAPI::Context.activate_session`.

This is handled automatically behind the scenes if you use ShopifyApp's [session controllers](https://github.com/Shopify/shopify_app/blob/main/docs/shopify_app/sessions.md). | | `api_version` | `String` | Default value is `nil`. When `nil` is passed in, api version is inferred from [`ShopifyAPI::Context.setup`](https://github.com/Shopify/shopify-api-ruby/blob/main/README.md#setup-shopify-context).| Examples: ```ruby # Create a default client with `ShopifyAPI::Context.api_version` # and the active session from `ShopifyAPI::Context.active_session` client = ShopifyAPI::Clients::Rest::Admin.new # Create a client with a specific session "my_session" client = ShopifyAPI::Clients::Rest::Admin.new(session: my_session) # Create a client with active session from `ShopifyAPI::Context.active_session` # and a specific api_version - "unstable" client = ShopifyAPI::Clients::Rest::Admin.new(api_version: "unstable") # Create a client with a specific session "my_session" and api_version "unstable" client = ShopifyAPI::Clients::Rest::Admin.new(session: my_session, api_version: "unstable") ``` ### Methods The `ShopifyAPI::Clients::Rest::Admin` client offers the 4 core request methods: - `get` - `delete` - `post` - `put` #### Input Parameters Each method can take the parameters outlined in the table below. | Parameter | Type | Required in Methods | Default Value | Notes | | -------------- | -------------------------------------------------------- | :-----------------: | :-----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `path` | `String` | all | none | The requested API endpoint path. This can be one of two formats: | | `body` | `Hash(any(Symbol, String), untyped)` | `put`, `post` | none | The body of the request | | `query` | `Hash(any(Symbol, String), any(String, Integer, Float))` | none | none | An optional query object to be appended to the request url as a query string | | `extraHeaders` | `Hash(any(Symbol, String), any(String, Integer, Float))` | none | none | Any additional headers you want to send with your request | | `tries` | `Integer` | None | `1` | The maximum number of times to try the request _(must be >= 0)_ | **Note:** _These parameters can still be used in all methods regardless of if they are required._ #### Output ##### Success If the request is successful these methods will all return a [`ShopifyAPI::Clients::HttpResponse`](https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/clients/http_response.rb) object, which has the following methods: | Methods | Type | Notes | |---------|------|-------| | `code` |`Integer`| HTTP Response code, e.g. `200`| | `header` |`Hash{String, [String]}` | HTTP Response headers | | `body` | `Hash{String, Untyped}` | HTTP Response body | | `prev_page_info` | `String` | See [Pagination](#pagination)| | `next_page_info` | `String` | See [Pagination](#pagination)| ##### Failure If the request has failed, an error will be raised describing what went wrong. You can rescue [`ShopifyAPI::Errors::HttpResponseError`](https://github.com/Shopify/shopify-api-ruby/blob/main/lib/shopify_api/errors/http_response_error.rb) and output error messages with `errors.full_messages` See example: ```ruby client = ShopifyAPI::Clients::Rest::Admin.new(session: session) response = client.get(path: "NOT-REAL") some_function(response.body) rescue ShopifyAPI::Errors::HttpResponseError => e puts fulfillment.errors.full_messages # {"errors"=>"Not Found"} # If you report this error, please include this id: bce76672-40c6-4047-b598-46208ab076f0. ``` ### Usage Examples #### Perform a `GET` request ```ruby # Create a new client. client = ShopifyAPI::Clients::Rest::Admin.new(session: session) # Use `client.get` to request the specified Shopify REST API endpoint, in this case `products`. response = client.get(path: "products") # Do something with the returned data some_function(response.body) ``` _For more information on the `products` endpoint, [check out our API reference guide](https://shopify.dev/docs/api/admin-rest/latest/resources/product)._ #### Perform a `POST` request ```ruby # Create a new client. client = ShopifyAPI::Clients::Rest::Admin.new(session: session) # Build your post request body. body = { product: { title: "Burton Custom Freestyle 151", body_html: "\u003cstrong\u003eGood snowboard!\u003c\/strong\u003e", vendor: "Burton", product_type: "Snowboard", } } # Use `client.post` to send your request to the specified Shopify Admin REST API endpoint. # This POST request will create a new product. client.post({ path: "products", body: body, }); ``` _For more information on the `products` endpoint, [check out our API reference guide](https://shopify.dev/docs/api/admin-rest/latest/resources/product)._ #### Perform a `PUT` request ```ruby # Create a new client. client = ShopifyAPI::Clients::Rest::Admin.new # Update product title body = { product: { title: "My cool product" } } # Use `client.put` to send your request to the specified Shopify Admin REST API endpoint. # This will update product title for product with ID client.put(path: "products/.json", body: body) ``` _For more information on the `products` endpoint, [check out our API reference guide](https://shopify.dev/docs/api/admin-rest/latest/resources/product)._ #### Accessing Rate Limit information The REST resources have `api_call_limit` and `retry_after` can be found on the Resource class. These values correspond to the `X-Shopify-Shop-Api-Call-Limit` and `Retry-After` [headers](https://shopify.dev/docs/api/usage/rate-limits#rest-admin-api-rate-limits) respectively. ```ruby product = ShopifyAPI::Product.find(session: session, id: 12345) # X-Shopify-Shop-Api-Call-Limit: 32/40 request_count = ShopifyAPI::Product.api_call_limit[:request_count] # 32 bucket_size = ShopifyAPI::Product.api_call_limit[:bucket_size] # 40 retry_after = ShopifyAPI::Product.retry_request_after ``` ### Pagination This library also supports cursor-based pagination for REST Admin API requests. [Learn more about REST request pagination](https://shopify.dev/docs/api/usage/pagination-rest). #### REST Admin Client After making a request, the `next_page_info` and `prev_page_info` can be found on the response object and passed as the `page_info` query param in other requests. An example of this is shown below: ```ruby client = ShopifyAPI::Clients::Rest::Admin.new(session: session) response = client.get(path: "products", query: { limit: 10 }) next_page_info = response.next_page_info if next_page_info next_page_response =client.get(path: "products", query: { limit: 10, page_info: next_page_info }) some_function(next_page_response) end ``` #### REST Resource Similarly, when using REST resources the `next_page_info` and `prev_page_info` can be found on the Resource class and passed as the `page_info` query param in other requests. An example of this is shown below: ```ruby products = ShopifyAPI::Product.all(session: session, limit: 10) loop do some_function(products) break unless ShopifyAPI::Product.next_page? products = ShopifyAPI::Product.all(session: session, limit: 10, page_info: ShopifyAPI::Product.next_page_info) end ``` [Back to guide index](../README.md)