Extended Usage¶
To parse a RAML file, include ramlfications in your project and call the parse function:
>>> import ramlfications
>>> RAML_FILE = "/path/to/my-api.raml"
>>> api = ramlfications.parse(RAML_FILE)
Configuration¶
Perhaps your API supports response codes beyond what IETF supports (default for this parser). Or maybe you implemented your own authentication scheme that your API uses I hope not!.
Example configuration file:
[main]
validate = True
[custom]
append = True
resp_codes = 420, 421, 422
auth_schemes = oauth_3_0, oauth_4_0
media_types = application/vnd.github.v3, foo/bar
protocols = FTP
raml_versions = 0.8
Feed the configuration into the parse function like so:
>>> import ramlfications
>>> RAML_FILE = "/path/to/my-api.raml"
>>> CONFIG_FILE = "/path/to/my-config.ini"
>>> api = ramlfications.parse(RAML_FILE, CONFIG_FILE)
RAML Root Section¶
In following the RAML Spec’s Root Section definition, here is how you can access the following attributes:
The Basics¶
>>> api.title
'My Other Foo API'
>>>
>>> api.version
v2
>>> api.base_uri
'https://{domainName}.foo.com/v2'
>>> api.base_uri_parameters
[<URIParameter(name='domainName')>]
>>>
>>> api.protocols
['HTTPS']
API Documentation¶
>>> api.documentation
[<Documentation(title='The Foo API Docs')>]
>>> doc = api.documentation[0]
>>> doc.title
'The Foo API Docs'
Docs written in the RAML file should be written using Markdown.
This also applies to any description
parameter.
With ramlfications
, documentation content and descriptions can either be viewed raw, or in parsed HTML.
>>> doc.content
'Welcome to the _Foo API_ specification. For more information about\nhow to use the API, check out [developer site](https://developer.foo.com).\n'
>>>
>>> doc.content.html
u'<p>Welcome to the <em>Foo API</em> specification. For more information about\nhow to use the API, check out <a href="https://developer.foo.com">developer site</a>.</p>\n'
Check out API Definition for full definition of RootNode
and its associated attributes and objects.
Security Schemes¶
RAML supports OAuth 1, OAuth 2, Basic & Digest, and any authentication scheme self-defined with an x-{other}
header.
To parse auth schemes:
>>> api.security_schemes
[<SecurityScheme(name='oauth_2_0')>]
>>> oauth2 = api.security_schemes[0]
>>> oauth2.name
'oauth_2_0'
>>> oauth2.type
'OAuth 2.0'
>>> oauth2.description
'Foo supports OAuth 2.0 for authenticating all API requests.\n'
>>> oauth2.description.html
u'<p>Foo supports OAuth 2.0 for authenticating all API requests.</p>\n'
And its related Headers and Responses:
>>> oauth2.described_by
{'headers': [<Header(name='Authorization')>], 'responses': [<Response(code='401')>, <Response(code='403')>]}
>>> first_header = oauth2.described_by['headers'][0]
>>> first_header
<HeaderParameter(name='Authorization')>
>>> first_header.name
'Authorization'
>>> first_headers.description
'Used to send a valid OAuth 2 access token.\n'
>>> first_headers.description.html
u'<p>Used to send a valid OAuth 2 access token.</p>\n'
>>> resps = oauth2.described_by['responses']
>>> resps
[<Response(code='401')>, <Response(code='403')>]
>>> resp[0].code
401
>>> resp[0].description.raw
'Bad or expired token. This can happen if the user revoked a token or\nthe access token has expired. You should re-authenticate the user.\n'
Authentication settings (available for OAuth1, OAuth2, and any x-header that includes “settings” in the RAML definition).
>>> oauth2.settings.scopes
['foo-read-private', 'foo-modify-public',..., 'user-read-email-address']
>>> oauth2.settings.access_token_uri
'https://accounts.foo.com/api/token'
>>> oauth2.settings.authorization_grants
['code', 'token']
>>> oauth2.settings.authorization_uri
'https://accounts.foo.com/authorize'
Check out API Definition for full definition of SecuritySchemes
, Header
, Response
and their associated attributes and objects.
Traits & Resource Types¶
Traits & resource types help when API definitions get a bit repetitive. More information can be found in the RAML spec for resource types and traits.
Resource Types¶
>>> api.resource_types
[<ResourceTypeNode(name='collection')>, <ResourceTypeNode(name='member')>]
>>> collection = api.resource_types[0]
>>> collection.name
'collection'
>>> collection.description
'The collection of <<resourcePathName>>'
>>> collection.usage
'This resourceType should be used for any collection of items'
>>> collection.method
'get'
>>> get.optional
False
Traits¶
>>> api.traits
[<TraitNode(name='filtered')>, <TraitNode(name='paged')>]
>>> paged = api.traits[1]
>>> paged.query_params
[<QueryParameter(name='offset')>, <QueryParameter(name='limit')>]
>>> paged.query_params[0].name
'offset'
>>> paged.query_params[0].description
'The index of the first track to return'
Mapping of Properties and Elements from Traits & Resource Types to Resources¶
When a resource has a trait and/or type assigned to it, or a resource type has another resource type or a trait assigned to it, it inherits its properties.
Also, the RAML Spec allows for parameters within Traits and ResourceTypes, denoted by double brackets within the Trait/ResourceType definition, e.g. <<parameter>>
. After the parsing of the API definition, the appropriate parameters are filled in for the respective resource.
For example, a simplified RAML file:
#%RAML 0.8
title: Example API - Mapped Traits
version: v1
resourceTypes:
- searchableCollection:
get:
queryParameters:
<<queryParamName>>:
description: |
Return <<resourcePathName>> that have their <<queryParamName>>
matching the given value
<<fallbackParamName>>:
description: |
If no values match the value given for <<queryParamName>>,
use <<fallbackParamName>> instead
- collection:
usage: This resourceType should be used for any collection of items
description: The collection of <<resourcePathName>>
get:
description: Get all <<resourcePathName>>, optionally filtered
post:
description: Create a new <<resourcePathName | !singularize>>
traits:
- secured:
description: A secured method
queryParameters:
<<tokenName>>:
description: A valid <<tokenName>> is required
- paged:
queryParameters:
numPages:
description: The number of pages to return, not to exceed <<maxPages>>
/books:
type: { searchableCollection: { queryParamName: title, fallbackParamName: digest_all_fields } }
get:
is: [ secured: { tokenName: access_token }, paged: { maxPages: 10 } ]
When parsed, the Python notation would look like this:
>>> RAML_FILE = "/path/to/foo-api.raml"
>>> api = parse(RAML_FILE)
# accessing API-supported resource types
>>> api.resource_types
[<ResourceTypeNode(method='GET', name='searchableCollection')>,
<ResourceTypeNode(method='POST', name='collection')>,
<ResourceTypeNode(method='GET', name='collection')>]
>>> api.resource_types[0].query_params
[<QueryParameter(name='<<queryParamName>>')>,
<QueryParameter(name='<<fallbackParamName>>')>]
>>> api.resource_types[0].query_params[0].description
Return <<resourcePathName>> that have their <<queryParamName>> matching the given value
# accessing API-supported traits
>>> api.traits
[<TraitNode(name='secured')>, <TraitNode(name='paged')>]
>>> api.traits[0].query_params
[<QueryParameter(name='numPages')>]
>>> api.traits[0].query_params[0].description
The number of pages to return, not to exceed <<maxPages>>
# accessing a single resource
>>> books = api.resources[0]
>>> books
<ResourceNode(method='GET', path='/books')>
>>> books.type
{'searchableCollection': {'fallbackParamName': 'digest_all_fields', 'queryParamName': 'title'}}
>>> books.traits
[<TraitNode(name='secured')>, <TraitNode(name='paged')>]
>>> books.query_params
[<QueryParameter(name='title')>, <QueryParameter(name='digest_all_fields')>,
<QueryParameter(name='access_token')>, <QueryParameter(name='numPages')>]
>>> books.query_params[0].description
Return books that have their title matching the given value
>>> books.query_params[3].description
The number of pages to return, not to exceed 10
Check out API Definition for full definition of traits
and resources
, and its associated attributes and objects.
Resources¶
“Resources” are defined in the RAML Spec’s Resource Section and is a
relative URI (relative to the base_uri
and, if nested, relative to
its parent URI).
For example, Foo API defines /foo/bar
as a resource (a
“top-level resource” to be exact). It also defines /{id}
under /foo/bar
,
making /{id}
a nested resource, relative to /foo/bar
. The relative path
would be /foo/bar/{id}
, and the absolute URI path would be
https://api.foo.com/v2/foo/bar/{id}
.
>>> api.resources
[<Resource(method='GET', path='/foo')>,..., <Resource(method='DELETE', path='/foo/bar/{id}')>]
>>>
>>> foo_bar = resources[-1]
>>> foo_bar.name
'/{id}'
>>> foo_bar.description
'[Delete a foo bar](https://developer.foo.com/api/delete-foo-bar/)\n'
>>> foo_bar.description.html
u'<p><a href="https://developer.foo.com/api/delete-foo-bar/">Delete a foo bar</a></p>\n'
>>> foo_bar.display_name
'foo bar'
>>> foo_bar.method
'delete'
>>> foo_bar.path
'/foo/bar/{id}'
>>> foo_bar.absolute_uri
'https://api.foo.com/v2/foo/bar/{id}'
>>> foo_bar.uri_params
[<URIParameter(name='id')>]
>>>
>>> uri_param = foo_bar.uri_params[0]
>>> uri_param.required
True
>>> uri_param.type
'string'
>>> uri_param.example
'f0ob@r1D'
>>> foo_bar.parent
<Resource(method='GET', path='/foo/bar/')>
Check out API Definition for full definition of what is available for a resource
object, and its associated attributes and objects.