LiveRamp / reslang

A language for describing resource-oriented APIs & turning them into Swagger or resource diagrams. Oriented around the concepts we want to expose in the APIs.
Apache License 2.0
23 stars 7 forks source link

Response object must not contain "required" parameters #20

Closed pratikmallya closed 4 years ago

pratikmallya commented 4 years ago

When describing the results on GET endpoints for a resource:

"Cars Api"
namespace {
    title "Make and Get Cars"
    version 0.1.0
}

"A Car Garage"
configuration-resource v0/cars {
    id: string
    make: string
  nitro: string mutable optional
    /operations
        "Get a single Car"
        GET
            "Invalid Argument" 400 StandardError
        "Create a Car"
        POST
            "Invalid Argument" 400 StandardError
}

The generated swagger contains an object specification for a successful response to the GET request as:

    v0-carsOutput:
      type: object
      properties:
        id:
          description: ''
          type: string
        make:
          description: ''
          type: string
        nitro:
          description: ''
          type: string
      required:
        - id
        - make

The required attribute is incorrectly generated. While the nitro option for a car is an optional property when POSTing a request, it is a required property when a GET request is made to get a car, since a car's description must include whether or not it has nitro installed.

Full Generated Swagger:

openapi: 3.0.1
info:
  title: Make and Get Cars
  description: Cars Api
  version: 0.1.0
servers:
  - url: 'https://api.liveramp.com/test'
tags:
  - name: v0/cars
    description: (configuration) A Car Garage
paths:
  /v0/cars:
    post:
      tags:
        - v0/cars
      operationId: Create v0/cars
      description: Create a Car
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/v0-carsInput'
      responses:
        '201':
          description: v0/cars created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    description: ''
                    type: string
        '400':
          description: Invalid Argument
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StandardError'
  '/v0/cars/{id}':
    get:
      tags:
        - v0/cars
      operationId: Get 1 v0-cars
      description: Get a single Car
      responses:
        '200':
          description: v0/cars retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/v0-carsOutput'
        '400':
          description: Invalid Argument
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StandardError'
      parameters:
        - in: path
          name: id
          required: true
          description: ''
          schema:
            type: string
components:
  parameters: {}
  schemas:
    v0-carsInput:
      type: object
      properties:
        make:
          description: ''
          type: string
        nitro:
          description: ''
          type: string
      required:
        - make
    v0-carsOutput:
      type: object
      properties:
        id:
          description: ''
          type: string
        make:
          description: ''
          type: string
        nitro:
          description: ''
          type: string
      required:
        - id
        - make
    StandardError:
      type: object
      properties:
        httpStatus:
          description: HTTP error status code for this problem
          type: number
        errorCode:
          description: 'Service specific error code, more granular'
          type: string
        message:
          description: 'General, human readable error message'
          type: string
      required:
        - httpStatus
        - errorCode
        - message
liveandrew commented 4 years ago

not 100% clear what you want. A REST GET verb always has a single id

it sounds like you want a MULTIGET. this always returns a collection, and is most commonly known as a query. to effect this, put "query" after nitro and add the verb MULTIGET.

this is all covered in RFC API-3 and also the reference guide on github for reslang

pratikmallya commented 4 years ago

not 100% clear what you want.

I would like the response from GET to be described accurately. In the example, the response is described as:

    v0-carsOutput:
      type: object
      properties:
        id:
          description: ''
          type: string
        make:
          description: ''
          type: string
        nitro:
          description: ''
          type: string
      required:
        - id
        - make

which is saying that the id and make attributes are required in the response, while the response from GET must return all 3 attributes. i.e all 3 attributes are required. Does that clarify the ask?

A REST GET verb always has a single id

I don't believe I said anywhere that it doesn't.

it sounds like you want a MULTIGET. this always returns a collection, and is most commonly known as a query. to effect this, put "query" after nitro and add the verb MULTIGET.

Nope, I want to GET a single resource, not multiple resources so the MULTIGET is not relevant.

liveandrew commented 4 years ago

ah, apologies, i misunderstood.

i've reworked the way attributes are marked as included for a given set of verbs and whether they are optional or not. please see the reference manual here under "Attribute modifiers" for more info: https://github.com/LiveRamp/reslang/blob/master/docs/reference.md

Here's a simple example:

configuration-resource Car {
    id: string
    make: string
    nitro: string mutable optional-post
    created: datetime output
    location: string mutable optional-put
    /operations
        GET POST PUT PATCH
}

This results in the following fields:

POST required=make and location, optional=nitro PUT required=nitro, optional=location PATCH optional=nitro and location GET required=id, make, nitro, created, location

The underlying intuition is that you mark fields are mutable if you want to be able to change them with PUT or PATCH, and you can mark something as output only by using "output".

You can then mark things as optional by using "optional" or "optional-post" etc for specific verbs. PATCH always has every field as optional.

Please let me know if this is not sufficient by providing an example and also re-opening this issue.

Commit: https://github.com/LiveRamp/reslang/commit/7047ee601a15d462318f68638c8e1172f2e8d7bb