Sinatra API Versioning - ruby

I'm new to APIs and Sinatra and I was wondering if there are any good gems for properly versioning a REST API using Sinatra. I'm using a namespace right now like this:
namespace '/api/v1' do
#routes and stuff here
end
So if I had a version 2, I would just have to create another namespace I suppose.

In your config.ru file, you can specify the mapping:
map('/v2') { run ClassNameV2 }
map('/v1') { run ClassNameV1 }

Related

How to do a basic GraphQL query to Shopify with Ruby

I'm trying to do a basic GraphQL query to a Shopify store with Sinatra. Could someone help me figure out what I'm doing wrong? I looked at their API to do this:
require 'shopify_api'
require 'sinatra'
class App < Sinatra::Base
get '/' do
shop = 'xxxx.myshopify.com'
token = 'shpat_xxxxxxxxxxxxxxxxxxxxxx'
session = ShopifyAPI::Session.new(domain: shop, token: token, api_version: "2021-04")
ShopifyAPI::Base.activate_session(session)
ShopifyAPI::GraphQL.initialize_clients
client = ShopifyAPI::GraphQL.client
SHOP_NAME_QUERY = client.parse <<-'GRAPHQL'
{
shop {
name
}
}
GRAPHQL
result = client.query(SHOP_NAME_QUERY)
result.data.shop.name
end
end
Which gives this error but I don't want to use Rake or Rails. Is it possible to do a GraphQL query to Shopify with Ruby?
ShopifyAPI::GraphQL::InvalidClient at /
Client for API version 2021-04 does not exist because no schema file exists at `shopify_graphql_schemas/2021-04.json`. To dump the schema file, use the `rake shopify_api:graphql:dump` task
As the error states, you need to first dump the schema (see this link: https://github.com/Shopify/shopify_api/blob/v9/docs/graphql.md#dump-the-schema).
Then you create a shopify_graphql_schemas directory in the same root as your ruby script, and put the generated JSON there.
Like stated in the comments, this requires a Rake task, so you need to be using Rails.
If your project doesn't use Rails, you need to do a quick workaround.
You create a temporary barebones Rails project, then generate the dump using that project (you can delete the project when you're done with this).
It's a bit hacky, but it's the only thing I can see that would work.
New link to schema dump
https://github.com/Shopify/shopify_api/blob/v9/docs/graphql.md#dump-the-schema
You need to use something like this
rake shopify_api:graphql:dump SHOP_DOMAIN="SHOP_NAME.myshopify.com" ACCESS_TOKEN="SHOP_TOKEN" API_VERSION=2022-04
Old one doesn't work anymore

How to migrate a modular Sinatra app to AWS Lambda

I have a modular Sinatra app that runs fine under rackup, that is with a config.ru that has three 'use' statements and one run statement. I am trying to get my head around how to port the application to AWS lambda where API_gateway will provide web server services and just call my app.
I am using the recommended lambda.rb script from https://github.com/aws-samples/serverless-sinatra-sample/blob/master/lambda.rb as my entrypoint. What I don't get is how, in the AWS Lambda micro-clime, do I assemble the modules/layers of my application without rackup and config.ru?
I assume that my noob brain is just missing something really basic in spite of the fact that I have read every blog post, bit of Sinatra and Rack documentation I know of, and the great "Sinatra Up and Running" book. What am I missing?
Upon re-reading the book, "Sinatra: Up and Running" again, it seems that there is a fairly elegant solution. If I set up my lambda.handler entrypoint to point to a simple Sinatra router, then it will be the router that composes the individual controllers into a 'system' which will handle all of my end points. the example from the book:
Example 4-32. Using Sinatra as router
require 'sinatra/base'
class Foo < Sinatra::Base
get('/foo') { 'foo' }
end
class Bar < Sinatra::Base
get('/bar') { 'bar' }
end
class Routes < Sinatra::Base
get('/foo') { Foo.call(env) }
get('/bar') { Bar.call(env) }
end
run Routes
Of course, in my case, I won't need the 'run Routes' line. I will just have my lambda.handler call Routes, as in Routes.call. This seems very doable!

Combine Rack::Builder and Rack::Cascade

Sorry if this question is a duplication of another question, but i haven't found it yet.
I have some Grape APIs (which are Rack apps) and one of them (the user API) uses a middleware for authentication.
In my config.ru file i combined all APIs to one app via Rack::Cascade. Here's the code:
user_management = Rack::Builder.new {
use Middleware
run UserAPI.new
}
app = Rack::Cascade.new [
user_management,
ExampleAPI1,
ExampleAPI2,
ExampleAPI3
]
The problem is that the middleware is called every time when any of the APIs gets a request.
Does anybody have any advice on how to use the middleware only when the user API gets a request?
The answer to this question is that I had to remove the resources (e.g. resource :user) from the APIs and then use Rack::Builder as follows:
app = Rack::Builder.new {
map '/user' do
use Middleware
run ExampleAPI1
end
map '/items' do
run ExampleAPI2
end
map '/locations' do
run ExampleAPI3
end
map '/reports' do
run ExampleAPI4
end
}
The problem with Rack::Cascade was that it tries every app from top to bottom until it finds the a suitable endpoint

Integrating Ember.js with a simple Sinatra backend

There is a lot of documentation of how to structure and create Ember.js apps with Rails as a backend. Pupular solutions are to use gems as ember-rails and ember-source or the all in one ember-appkit-rails.
However i'm trying to create a simple Sinatra app that handle a JSON only backend with Ember.js as the frontend.
The few resources that i found seems a little outdated, so i'm looking for simple way to do that.
So my question is:
How i integrate Ember.js with a simple Sinatra backend ??
Examples of how to do so will be appreciated.
There is a very simple repo on Github, that could serve as a starting point for you. Just grab the code, start the sinatra app server, and point your Ember datasource to it, like this:
App.MyRestAdapter = DS.RestAdapter.extend({
host: 'http://localhost:3000',
namespace: 'api'
});
App.store = DS.Store.create({
adapter: 'MyApp.MyRestAdapter'
});
You could also look into the source of Travis CI, as they use Sinatra (travis-api) and Ember.js (travis-web).

Using custom classes with Sinatra

I'm developing a Sinatra application. To simplify the structure for an easier future support I added a few custom classes, located in separate files. What I'm trying to do is to make them use existing helpers and sinatra's own functionality (models, sessions, etc) without repeating the code.
For example, I have a helper to_html(text) and I'd like to use it both inside sinatra routes and in my own classes, which are also to be used inside routes.
My sinatra app is written in classic style (if it matters for your suggestion).
Is it possible?
Assuming you have a helpers directory in the root of the project, you could do something like this from inside your app file you use to run the server.
%w(helpers).each { |p| Dir[File.join(File.dirname(__FILE__), p, "*.rb")].each { |file| require file } }
You will need to include your routes below this for it to work. To make this even cleaner, you can also have a routes/controllers directory. Simply add 'routes' to that array as such:
%w(helpers routes).each { |p| Dir[File.join(File.dirname(__FILE__), p, "*.rb")].each { |file| require file } }
This will require all of your helpers THEN your routes.

Resources