Svelte
Svelte is a Swagger-to-Ruby object mapper.
It reads a Swagger specification file in JSON, and automatically generates Resource Classes with static methods to represent the various HTTP endpoints.
Installation
Add this line to your application's Gemfile:
gem "svelte"
And then execute:
$ bundle
Or install it yourself as:
$ gem install svelte
Usage
Point a service at an actual API spec.
You may pass in a URL pointing to a Swagger spec or the JSON directly:
service = Svelte::Service.create(url: "http://path/to/swagger/spec/resource.json", module_name: 'PetStore')
service = Svelte::Service.create(json: "{ <JSON here> }", module_name: 'PetStore')
This will build a dynamically generated client on top of Svelte::Service::PetStore
.
The structure of the new module will be based on the API paths and their respective operations. Let's look at an example. Using the complete PetStore spec, we can find the following path:
"/pet/findByStatus": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"description": "Multiple status values can be provided with comma separated strings",
"operationId": "findPetsByStatus",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "status",
"in": "query",
"description": "Status values that need to be considered for filter",
"required": true,
"type": "array",
"items": {
"type": "string",
"enum": [
"available",
"pending",
"sold"
],
"default": "available"
},
"collectionFormat": "multi"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"400": {
"description": "Invalid status value"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
}
The path contains two parts: pet
and findByStatus
. This will generate
the following hierarchy in the new module:
Svelte::Service::PetStore::Pet::FindByStatus
We can see the path has one get
operation. A method will be generated in the
FindByStatus
module based on the operationId
Swagger attribute, which will
have the following signature:
Svelte::Service::PetStore::Pet::FindByStatus.find_pets_by_status(
request_payload,
request_options = {}
)
Where request_payload
is a Hash
representing the parameters of the operation
and request_options
, defaulting to an empty Hash
, will be a Hash
of
options to pass to the request.
In our case, the parameters would look like this:
request_parameters = {
status: ['available', 'pending']
}
Responses
Svelte will return a Faraday::Request
object as a response to a call.
Models
Svelte also provides generators for Swagger models. They allow an easy way
to programmatically create and validate requests.
They also provide an as_json
that will generate a valid json body for
a given request.
Consider the definitions key of this Swagger model:
{
"definitions": {
"MoneyView": {
"id": "MoneyView",
"description": "",
"required": [
"amount",
"currencyCode"
],
"extends": "",
"properties": {
"amount": {
"type": "number",
"format": "double",
"description": "Decimal amount"
},
"currencyCode": {
"type": "string",
"description": "ISO 3 letter currency code"
}
}
}
}
}
In Svelte you can generate the ruby mapper like this:
class MoneyRequest
extend Svelte::ModelFactory
define_models_from_file(path_to_models_json_file)
end
view = MoneyRequest::MoneyView.new
view.valid? # false
view.validate # {"currencyCode"=>"Invalid parameter: Missing required parameter", "amount"=>"Invalid parameter: Missing required parameter"}
view.currencyCode = "GBP"
view.amount = 40.00
view.valid? # true
view.as_json # {:currencyCode=>"GBP", :amount=>40.0}
Service Options
When creating a client from the API spec, you can pass an options
hash that will determine how the HTTP client interacts with your service.
Svelte::Service.create(
url: "http://path/to/swagger/spec/resource.json",
module_name: 'PetStore',
options: {
host: 'somehost.com',
base_path: '/api/v1',
protocol: 'https',
auth: {
basic: {
username: "user",
password: "pass"
}
},
headers: {
runas: 'otheruser'
}
})
The available options are:
-
host
: overrides thehost
value found in the Swagger API spec, used when making API requests -
base_path
: overrides thebasePath
value found in the Swagger API spec, used when making API requests -
protocol
: overrides the network protocol used (default value is "http" when not present) -
auth
: sets optional authorization headers. Possible values:-
{ basic: { username: "value", password: "value" } }
: sets basic authentication credentials -
{ token: "Bearer 12345" }
: sets a generic Authorization header (in this case a Bearer token12345
)
-
-
headers
: a collection of arbitrary key/value pairs converted to HTTP request headers included with each outgoing request
Request Options
You can specify a timeout option on a per request basis. If the request times out a Svelte::TimeoutError
exception
will be raised.
begin
Svelte::Service::PetStore::Pet::FindByStatus.find_pets_by_status(request.as_json, { timeout: 10 })
rescue Svelte::TimeoutError => e
handle_timeout_error(e)
end
## Limitations
Svelte is still a work in progress gem and it lacks some features that will be implemented in the future. Feel free to request or comment on what you'd like to see supported. Here is a non exhaustive list of the pitfalls we've identified so far:
- Supports
application/json
request and response types only - API calls return a raw [Faraday::Response] objects. We'll support returning dynamically generated model responses based on the Swagger spec response schema
- Request parameter validation is only done for url based parameters.
It'd be possible to add validations to all parameters of the request.
In fact the
ModelFactory
already provides that functionality, but it requires the client to callvalid?
on the requests to perform the validation. This should happen automatically
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
to create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
- Fork it ( https://github.com/notonthehighstreet/svelte/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request