URI Construction

RESTful APIs use Uniform Resource Identifiers (URIs) to address resources, ONAP projects should comply with a unified URI standard to implement the microservices.

  • URI structure (Mandatory)
    URI structure http://[host]:[port]/api/{service name}]/v{version number}/{resource}
    The URI is comprised of a fixed base uri /api/{service name}]/v{version number} and the resource path. Only major version number is used in the URI. An example: http://127.0.0.1:8080/api/petstore/v1/pets/dogs
  • CRUD function names should not be used in URIs. Instead, CRUD actions should be represented by HTTP methods. Below is the proposed methodology to implement CRUD operations in a RESTful API. (Recommended)

    ResourcePOSTGETPUTDELETE
    /api/petstore/v1/pets/dogsCreate a new dogList dogsReplace dogs with new dogs(Bulk update) Delete all dogs
    /api/petstore/v1/pets/dogs/baileyError Show dogIf exist update dog else ERROR Delete dog

    Do not use:

 /api/petstore/v1/pets/getalldogs

 /api/petstore/v1/pets/createdog

 /api/petstore/v1/pets/deletedog

  • A trailing forward slash (/) should not be included in URIs (Mandatory)

A forward slash (/) adds no semantic value and may cause confusion. RESTful API’s should not expect a trailing slash and should not include them in the links that they provide to clients.

  • Forward slash separator (/) must be used to indicate a hierarchical relationship (Mandatory)
  • Use Hyphens (-) instead of Underscores (_)  if separation of words is needed in the URI (May have conflict with SOL, TBD)

 Underscores (_) can be hidden by the underline of URIs in browsers.

  • Lowercase letters should be preferred in URI paths (Recommended)

When convenient, lowercase letters are preferred in URI paths since capital letters can sometimes cause problems. RFC 3986 defines URIs as case-sensitive except for the scheme and host components.

  • File extensions should not be included in URIs (Recommended)

A REST API should not include artificial file extensions in URIs to indicate the format of a message’s entity body. Instead, they should rely on the media type, as communicated through the Content-Type header, to determine how to process the body’s content. 

  • A plural noun should be used for collection names (Mandatory)
    For example, the URI for a collection of dog documents uses the plural noun form of its contained resources: /api/petstore/v1/pets/dogs
  • A singular noun should be used for document names (Mandatory)
    For example, the URI for a single dog document would have the singular form: /api/petstore/v1/pets/dogs/bailey

Versioning

API is a public contract between a Server and a Consumer, so it's crucial to make sure the changes are backwards compatible. We need to introduce new versions of the API while still allowing old versions to be accessible when it's necessary. So a versioning mechanism should be considered.

  • The version in the swagger file and URI (Mandatory)
    The main idea is that there are two kinds of versions:
    • Major version: The version used in the URI and denotes breaking changes to the API. Internally, a new major version implies creating a new API and the version number is used to route to the correct implementation.
    • Minor and Patch versions: These are transparent to the client and used internally for backward-compatible updates. They should be reflected in the swagger files to inform clients about a new functionality or a bug fix. 

For example, if the version of a RESTful API of an ONAP component is 1.3.2, the Info Object of swagger file should look like

title: Swagger Sample App
description: This is a sample server Petstore server.
termsOfService: http://swagger.io/terms/
contact:
  name: API Support
  url: http://www.swagger.io/support
  email: support@swagger.io
license:
  name: Apache 2.0
  url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.3.2

The URI should look like: http://{host}/api/v1/pets

  • Version discovery (Optional)

Need to be discussed: Should ONAP adopt a version discovery mechanism like OpenStack?  :https://wiki.openstack.org/wiki/VersionDiscovery

HTTP response status codes

The server should always return the right HTTP status code to the client. (Recommended)

  • Standard HTTP status codes

200 – OK – Everything is working
201 – OK – New resource has been created
204 – OK – The resource was successfully deleted

304 – Not Modified – The client can use cached data

400 – Bad Request – The request was invalid or cannot be served. The exact error should be explained in the error payload. E.g. „The JSON is not valid“
401 – Unauthorized – The request requires a user authentication
403 – Forbidden – The server understood the request but is refusing it or the access is not allowed.
404 – Not found – There is no resource behind the URI.
422 – Unprocessable Entity – Should be used if the server cannot process the entity, e.g. if an image cannot be formatted or mandatory fields are missing in the payload.

500 – Internal Server Error – API developers should avoid this error. If an error occurs in the global catch blog, the stracktrace should be logged and not returned as in the response.

  • Use error payloads

All exceptions should be mapped in an error payload. Here is an example how a JSON payload should look like.

{
  "message": "Sorry, the requested resource does not exist",
  "code": 34
} 

Need to be discussed: Should ONAP define a unified error response format across projects?

Security

  • Token Based Authentication (Recommended)
    Ideally, microservices should be stateless so the service instances can be scaled out easily and the client requests can be routed to multiple independent service providers. A token based authentication mechanism should be used instead of session based authentication 
  • API-Token Authentication (Recommended)
    ONAP is supposed to be accessed by third-party apps such as OSS/BSS, in the authentication process a user is not involved. API-Token can be used in such cases.
  • Centralized Authentication/Authorization (Recommended)
    The MSB API Gateway can serve as the entry point to authenticate client requests and forwards them to the backend services, which might in turn invoke other services.
    MSB doesn't do the authentication itself, instead, MSB can work with a security provider to provide centralized Authentication or ONAP with its pluggable architecture.
  • Use https for external communication for security reason
    The MSB External API Gateway can translate the https request from the external systems to light weight http communication inside ONAP system. The individual projects don't have to handle the trivial details such as certification configuration and avoid the overhead of https inside ONAP system. 

Multiple tenants support

TBD

API Documentation(Swagger)

  • All the RESTful API must follow Swagger Specification for API documentation: http://swagger.io/specification (Recommended)
    The ONAP-Components must provide swagger files for its RESTful API definitions, there are two possible approaches. 
    • The developers write the Swagger file, then use CI system to generate the stub codes for implementation.
    • The developers write the Swagger annotation in the source codeI, then use CI system to generate the Swagger file.
  • The Swagger file should be placed under the base url of the service so the API definition could be discovered by clients or management tools at runtime.  (Recommended)
    For example, if the base url of peststore service is /api/petstore/v1/, the URL of swagger file should be /api/petstore/v1/Swagger.json

Appendix

Swagger Specification http://swagger.io/specification

Swagger UI https://swagger.io/swagger-ui/

Swagger code generator https://swagger.io/swagger-codegen/

Maven plugin to generate Swagger documents https://github.com/WASdev/tool.swagger.docgen

MSB Centralized Authentication & Authorization solution https://wiki.onap.org/download/attachments/3246982/Capture7.PNG?version=1&modificationDate=1495079131000&api=v2

Swagger SDK https://wiki.open-o.org/display/CLIEN/Swagger+SDK+for+Open-O



  • No labels

22 Comments

  1. user-67d6f

    Why don't we follow the swagger spec for writing the the REST API here ?

    1. I agree we should follow the swagger,  however,  Swagger is more about how to describe and document RESTful APIs. So we also need to define some unified standards/best practices on the REST API definition across the ONAP projects such as versioning, url, error code. This draft may not appropriate right now, I will work out a draft and submit as a start point for discussion.

      1. user-67d6f

        sure. 

        its better to make the consistency made on following aspects:

        1. Error response format in addition to just an error code
        2. singular and plural Entity header whether or not to be part of it
        3. base_path url format (including version) as you said
        4. AUTH token header
        5. Pagination (with index, start)
        6. I think tenancy may not come into picture for ONAP, if so then..


      2. This is not strictly true. Swagger is for documenting APIs. You can document VERY non-REST APIs using Swagger. Nothing in the Swagger spec limits you to documenting RESTful APIs. 

        1. That's a good point. Dose this sounds OK to you:  "All the RESTful API must follow Swagger Specification for API documentation"?

  2. I am one of the developers of the new DCAE framework (which should be pushed into ONAP soon) and it has many HTTP APIs. I want to make a comment on terminology.

    A lot of developers use the term "RESTful API" when really they mean "HTTP API". REST is one approach to writing HTTP APIs. It is a "design philosophy". However, it is not the only approach to writing HTTP APIs. Many APIs do not strictly adhere to REST. Example: AWS. Take a look at http://docs.aws.amazon.com/AmazonS3/latest/API/multiobjectdeleteapi.html. See the "POST /?delete HTTP/1.1"? Having a verb in the URL that you action on is not REST; this is an HTTP API. 

    I think forcing all developers to strictly adhere to REST would be a huge educational challenge. Even experienced developers, including myself, write APIs that are not strictly RESTful. I think REST is an often misunderstood or not-fully-understood topic. So, we should carefully consider whether we force all HTTP APIs to be RESTful or not. DCAE is probably "mostly RESTful" but there are definitely some violations and thus I would call the APIs "HTTP". 

    We use Swagger for documenting all of our HTTP APIs, so I agree with most of the above. However, Swagger allows you to document very non-RESTful APIs if you wanted to, so again, we need to be careful about the usage. You can document an HTTP API in Swagger that easily violates RESTful principles.


    1. Hi Tommy,

      While I agree that REST is not the only approach, I would like to say REST is the right approach to use HTTP. The example you mentioned here is a very specific case. According to rfc2616, DELETE should be idempotence. Obviously, if we execute"delete all" action multiple times, it may change the state of the server after the first execution because new objects could be created between these executions. So POST may be more appropriate in this scenario because POST is not supposed to be idempotence. Furthermore, when we look at the Amazon APIs, most of them are strictly RESTful style. There might be exceptions to the listed rules, I suggest we should at least agree on the principles and identify the exceptions case by case if needed.

  3. Is the example correct for the single document?

    I would have expected

    the URI for a single dog document would have the singular form: /api/petstore/v1/pets/dog/bailey

    1. An interesting point, It seems to me that Bailey is one of the dogs in the set, so using plurality makes sense here. What do you think?

    2. I believe the example is correct.  The single document (bailey) is part of the collection of dogs as implied by the hierarchy.  If we are to use the hierarchical model as implied by the above documentation, the higher elements should remain consistent.

      I don't believe there is a formal standard on this - but it is the common practice among REST users, for reasons captured well at https://stackoverflow.com/questions/6845772/rest-uri-convention-singular-or-plural-name-of-resource-while-creating-it


  4. As stated during the PTL call today, I would like to suggest some tools like described in the following EPIC (see JIRA - COMMON-9) about Integration with Swagger to design, build, document, and consume our ONAP RESTful API

    As an ONAP developer, I will integrate my source code with

    • Swagger Codegen to generate client libraries for my API
    • Swagger UI to generate interactive API documentation that lets any user try out the API calls directly in the browser.
    1. user-67d6f

      we tried to address these sort of problems in open-o by project called swagger-sdk https://wiki.open-o.org/display/CLIEN/Swagger+SDK+for+Open-O


  5. APPC is already using Swagger for it's APIs

    1.  Swagger is only part of the API Design Specification, please also take a look at other important items such as versioning, url contruct, etc. 

  6. I  want to note that, until later this year when Swagger adopts the Open API Specification 3.0, which supports full JSON Schema 4, it is not possible to express all APIs in Swagger as spec 2 is quite limited. In the current version of Swagger, critical things like "oneOf" are still not supported. You can read in this gigantic thread here: https://github.com/OAI/OpenAPI-Specification/issues/333. Currently it was impossible to document some of our API calls in Swagger because of these limitations (the subset of JSON Schema spec 2 uses was not expressive enough). 

    I do not know of the exact release date of Spec 3 or when Swagger will be updated to adopt it.  But full expression of our APIs in Swagger are not possible until then. 

    1. Since there is no 100% perfect solution for this question, we're trying to find and adopt the best suitable one on the table for ONAP. And the swagger is heading to the correct direction to fix these issues. As what I was saying, I suggest we should at least agree on the principles and identify the exceptions case by case if needed. 

  7. To Follow on the comment from Stephen towards the end of the meeting, here are some REST API guidelines in Telco space only, I am sure that there are many more (feel free to add to the list):

    TMF: https://www.tmforum.org/resources/standard/gb983-rest-api-design-guidelines-v1-0-1/ & https://projects.tmforum.org/wiki/display/API/API+Design+Guidelines

    ETSI NFV SOL: https://docbox.etsi.org/ISG/NFV/SOL/05-CONTRIBUTIONS/2017//NFVSOL(17)000050r3_SOL_REST_API_convention_collection_living_document.zip

    3GPP has one under construction as well: http://www.3gpp.org/DynaReport/32866.htm 

    Not saying that any of those are to be adopted as is, just providing some pointers to previous / ongoing efforts. In addition, there is lots of effort to e.g. autogenerate interfaces (including RESTful ones) from e.g. YANG and other models, which is related topic, but perhaps more in the domain of modeling related projects. 

    1. You may have some difficulty to access ETSI NFV SOL document.  I am in the process of getting this document made public available and updating it too. I will let you know when it is available. Meanwhile, if you are ETSI NFV members, you should be able to download it.

      1. Hi Thinh,

        Thanks for reaching out to help.

        I have successfully downloaded this document https://docbox.etsi.org/ISG/NFV/Open/Drafts/SOL005_Os-Ma-nfvo_APIs 

        I think we should align the ONAP specification with "4 General Aspects" clause, My expectation is that we could figure out the minimum but the most important set of rules to guide the REST API design of ONAP projects so the client and developers can have consistent and easy to use API for ONAP.  The date should be at least two weeks before M3 API freeze Aug. 24.

        We may also keep in mind that ONAP specification is not fixed and will be open for contribution and updating along with the development of ONAP platform, so after the official release of SOL, we still have chances to go back to improve this specification.

  8. The URI format above does not fit well for controllers based on OpenDaylight - or more generally, for controllers that expose RESTCONF interfaces. There are existing conventions in RESTCONF that are built in to OpenDaylight (and probably other controller platforms as well) that could make it difficult to meet the URI standards above exactly, but we can get fairly close.

    In RESTCONF, there are 3 different types of APIs:

    • Configuration data (also referred to as "config tree"), which stores the in flight view of network data (so it shows pending changes).  URI for such data begins with /restconf/config
    • Operational data (also referred to as the operational tree), which stores the current active view of network data.  URI for such data begins with /restconf/operational
    • RPCs

    I propose the following conventions for each of these types of RESTCONF APIs, based on the proposal above:

    • Config tree : /restconf/config/<service name>:v<version>/<resource> e.g. /restconf/config/neutron:v2.0/networks
    • Operational tree : /restconf/operational/<service name>:v<version>/<resource> e.g. /restconf/operational/neutron:v2.0/networks
    • RPC : /restconf/operations/<service name>:v<version>/<rpc name> e.g. /restconf/operations/SLI-API:v1.0/healthcheck



    1. Hi Dan, it's a very good point. Can you help add a paragraph in the specification about RESTCONF APIs?   

  9. It looks like this page was discussed last year, but still wanted to point out that the internet discussed this even earlier and seems to disagree with the conclusions reached on this page.

    I want my API to be versioned

    The first thing that people do when they want a versioned API is to shove a /v1/ in the URL. THIS IS BAD!!!!!1Accept solves this problem. What you're really asking for is "I'd like the version two representation of this resource." So use accept!

    http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http

    See also discussion at StackOverflow: https://stackoverflow.com/questions/972226/how-to-version-rest-uris