OpenAPI Specification Path: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(61 intermediate revisions by the same user not shown)
Line 2: Line 2:
* [[OpenAPI_Specification#paths|OpenAPI Specification]]
* [[OpenAPI_Specification#paths|OpenAPI Specification]]
=Overview=
=Overview=
The top level <code>[[OpenAPI_Specification#paths|paths]]</code> keyword introduce a map of '''paths''', keyed by their path value:
The top level <code>[[OpenAPI_Specification#paths|paths]]</code> keyword introduce a map of [[#Path|paths]], keyed by their path values:


<font size=-2>
<font size=-2>
Line 23: Line 23:
   [[#summary|summary]]:
   [[#summary|summary]]:
   [[#description|description]]:
   [[#description|description]]:
   [[#Operations|get]]: [...]
   [[#Operations|get]]: [...] <font color=teal># a GET /a interface method will be generated by server code generation</font>
   [[#Operations|put]]: [...]
   [[#Operations|put]]: [...] <font color=teal># a PUT /a interface method will be generated by server code generation</font>
   [[#Operations|post]]: [...]
   [[#Operations|post]]: [...] <font color=teal># a POST /a interface method will be generated by server code generation</font>
   [[#Operations|delete]]: [...]
   [[#Operations|delete]]: [...] <font color=teal># a DELETE /a interface method will be generated by server code generation</font>
   [[#Operations|options]]: [...]
   [[#Operations|options]]: [...] <font color=teal># ...</font>
   [[#Operations|head]]: [...]
   [[#Operations|head]]: [...]
   [[#Operations|patch]]: [...]
   [[#Operations|patch]]: [...]
Line 34: Line 34:
   servers:
   servers:
</font>
</font>
==Server Code Generation for Path/Operation Combinations==
For each path/operation combination, <code>[[Oapi-codegen#Code_Generation_for_OpenAPI_Specification_Path/Operation_Combinations|oapi-codegen]]</code> will generate a Go "Operation /Path" handler method in the <code>ServerInterface</code> interface object. The name of the methods will be given by <code>[[#operationId|operationId]]</code> value, with the first character uppercased.


=Path Templating=
=Path Templating=
Line 59: Line 61:
   description:  <font color=teal>'...'</font>
   description:  <font color=teal>'...'</font>
   [[#Parameters|parameters]]: [...]
   [[#Parameters|parameters]]: [...]
   [[#Responses|responses]]: [...]
   [[#responses|responses]]: [...]
   [[#Tags|tags]]: [...]
   [[#tags|tags]]: [...]
   [[#RequestBody|requestBody]]:
   [[#requestBody|requestBody]]:
   callbacks:
   callbacks:
   security:
   security:
Line 101: Line 103:
Surfaces in the generated code, as the generated server interface method comment.
Surfaces in the generated code, as the generated server interface method comment.
==<tt>description</tt>==
==<tt>description</tt>==
==<tt>responses</tt>==
{{External|https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responses-object}}
The <code>responses</code> field is required and lists all possible HTTP [[#Response|responses]] that may result from executing this operation.
===Response===
{{External|https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responseObject}}
The element must contain at least one response code. The definition is not expected to cover all possible HTTP response codes, because they may not be known in advance. However, the definition should cover a successful operation response and any known errors. The <code>default</code> map key may be used as a default response object for all HTTP codes that are not covered individually in the definition.
<syntaxhighlight lang='yaml'>
paths:
  /pets:
    get:
      [...]
      responses:
        200:
          description: Return all the pets the user has access to, as a list.
          headers: [...]
          links: [...]
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
</syntaxhighlight>


 
<span id='Empty_Response'></span>An empty response:
====Responses====
{{External|https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responses-object}}
The <code>responses</code> field is required and lists all possible HTTP responses that may result from executing this operation. The element must contain at least one response code. The definition is not expected to cover all possible HTTP response codes, because they may not be known in advance. However, the definition should cover a successful operation response and any known errors. The "default" map key may be used as a default response object for all HTTP codes that are not covered individually in the definition.
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
paths:
paths:
/a:
  /a:
  get:
    get:
    responses:
      [...]
      200:
      responses:
        [...]
        200:
      default:
          schema:
        [...]
            $ref: '#/components/schemas/Empty'
</syntaxhighlight>
The Empty type is declared in the <code>/components/schemas</code> as such: {{Internal|OpenAPI_Specification_Schemas#Empty_Type|Empty}}
====<tt>headers</tt>====
{{External|https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#headerObject}}
The header object follows the structure of a [[#Parameters|parameter]] object, with the exceptions that <code>name</code> must not be specified, it is given in the corresponding headers map, and <code>in</code> must not be specified, it is implicitly in header. <code>headers</code> is a container that maps a header name to its definition. The header names are case insensitive. If a header is specified by the an extension, such as [[Amazon_API_Gateway_Extension_to_OpenAPI#x-amazon-apigateway-integration|x-amazon-apigateway-integration]], it has to be declared in the [[#headers|headers]] section for the corresponding response, otherwise a template error is generated. Responses can include custom headers, or headers that implement a protocol like [[Cross-Origin_Resource_Sharing#Overview|CORS]].
<syntaxhighlight lang='yaml'>
200:
  [...]
  headers:
    Access-Control-Allow-Origin:
      description: some description
      schema:
        type: string
    Access-Control-Allow-Methods:
      description: some description
      schema:
        type: string
    Access-Control-Allow-Headers:
      description: some description
      schema:
        type: string
</syntaxhighlight>
</syntaxhighlight>
====RequestBody====
 
==<tt>requestBody</tt>==
{{External|https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#request-body-object}}
{{External|https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#request-body-object}}
Also see: {{Internal|REST_and_Hypermedia#Request_Body|REST Request Body}}
Also see: {{Internal|REST_and_Hypermedia#Request_Body|REST Request Body}}
====Tags====
==<tt>tags</tt>==
Each operation can be annotated with a list of tags. Tagged operations may be handled differently by tools and libraries. Optionally, each tag can get a "description" and an "externalDocs" in the global "tags" section on the root level. The tag names here should match those used in operations. The tag order in the global tags section also controls the default sorting in the UI. It is possible to use a tag at operation level even if it is not specified on the root level.
Each operation can be annotated with a list of tags. Tagged operations may be handled differently by tools and libraries. Optionally, each tag can get a <code>description</code> and an <code>externalDocs</code> in the global <code>[[OpenAPI_Specification#tags|tags]]</code> section on the root level. The tag names here should match those used in operations. The tag order in the global tags section also controls the default sorting in the UI. It is possible to use a tag at operation level even if it is not specified on the root level.
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
tags:
tags:
Line 146: Line 196:
       description:
       description:
       required: true|false
       required: true|false
      style: form
      [[#Parameter_Schema|schema]]: [...]
       deprecated: true|false
       deprecated: true|false
       [[#allowEmptyValue|allowEmptyValue]]: true|false
       [[#allowEmptyValue|allowEmptyValue]]: true|false
      [[#Parameter_Schema|schema]]: [...]
     - [...]
     - [...]
</font>
</font>
Line 183: Line 234:


==Parameter Schema==
==Parameter Schema==
=Examples=
==<tt>GET</tt> with Empty Response Body==
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
paths:
paths:
   /a:
   /pets:
     get:
     get:
       parameters:
       parameters:
         - name: test
         - name: tags
           in: query
           [...]
          type: string
      responses:
        200:
           schema:
           schema:
             $ref: '#/components/schemas/Empty'
             type: array
components:
            items:
  schemas:
              type: string
    Empty:
      type: object
</syntaxhighlight>
</syntaxhighlight>
=TODEPLETE=
=Operation Declaration and Implementation Examples=
<font color=darkkhaki>
The server code generation the following examples work in top of is done with: {{Internal|Oapi-codegen#Server_Code_Generation|<tt>oapi-codegen</tt>}}
==Response==
==Create a Resource Instance==
{{External|[https://swagger.io/specification/#responseObject Response Object]}}
Creation of new resources is conventionally implemented with <code>POST</code> in REST architectures.  
{{External|[https://swagger.io/docs/specification/2-0/describing-responses/ Describing Responses in OpenAPI 2.0]}}
 
A response is defined by its HTTP status code and the data returned in the [[#Response_Body|response body]] and/or [[#Response_Headers|headers]].
{{Internal|REST_and_Hypermedia#POST|HTTP POST}}
 
OpenAPI path specification:
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
200:
paths:
   description: 200 response
   /pets:
  schema:
    post:
    $ref: '#/definitions/Empty'
      operationId: CreatePet
    originalRef: '#/definitions/Empty'
      summary: Create a new Pet instance.
  headers:
      description: |
    Access-Control-Allow-Origin:
        CreatePet creates a new Pet instance, expecting all required state as arguments.
      type: 'string'
        It generates an unique ID. The method is NOT idempotent.
    Access-Control-Allow-Methods:
      requestBody:
      type: 'string'
        description: The state of the Pet to be added to the store.
    Access-Control-Allow-Headers:
        required: true
      type: 'string'
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PetPayload'
      responses:
        201:
          description: The state of a newly create instance, including the new ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
</syntaxhighlight>
The following types are used:
* <code>[[OpenAPI_Specification_Schemas#PetPayload|PetPayload]]</code> type.
* <code>[[OpenAPI_Specification_Schemas#Pet|Pet]]</code> type.
* <code>[[OpenAPI_Specification_Schemas#Error_Type|Error]]</code> type.
Server implementation:
<syntaxhighlight lang='go'>
func (s *PetStoreServer) CreatePet(ctx echo.Context) error {
var petPayload petstore.PetPayload
err := json.NewDecoder(ctx.Request().Body).Decode(&petPayload)
if err != nil {
return err
}
// create and store the pet, then return the result, the ID will be generated internally by NewPet()
p := petstore.NewPet(petPayload)
s.Lock()
defer s.Unlock()
s.pets[p.ID] = p
resp, err := json.Marshal(p)
if err != nil {
return err
}
_, err = ctx.Response().Write(resp)
return err
}
</syntaxhighlight>
Invocation:
<syntaxhighlight lang='bash'>
curl -H "Content-Type: application/json" -X POST -d '{"name":"Fido", "age":2, "tag":"blue"}' http://localhost:30000/pets
</syntaxhighlight>
</syntaxhighlight>
===<tt>description</tt>===
===TODO Create===
The description is required. Represents a short description of the response.
<font color=darkkhaki>The appropriate response should be 201. See [[HTTP_Status_Codes#201_Created|HTTP 201]] and the "Location" header may contain the URL of the new resource, see: {{Internal|REST_and_Hypermedia#POST|HTTP POST}}</font>
==Response Body==
===<tt>schema</tt>===
The schema keyword is used to describe the response body. A schema may define:
* a primitive type such as "string" or "number", used for plain text responses. Note that Amazon API Gateway warns if it encounters a primitive type.
* an object
* an array – typically used with JSON and XML APIs
* a file
* a reference - the schema can be defined in-line or defined at the root level of the document and referenced via [[#.24ref|$ref]]. This is useful if multiple responses share the same schema.


For reference models (<code>RefModel</code>), <tt>model.setReference("RefName")</tt> puts the model in the correct state to refer to:
==Get All Items as a JSON Array==
Reading resources is conventionally implemented with <code>GET</code> in REST architectures.  
 
{{Internal|REST_and_Hypermedia#GET|HTTP GET}}
 
OpenAPI path specification:
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
definitions:
paths:
   RefName:
   /pets:
     type: ...
     get:
      operationId: GetPets
      summary: Get all Pet instances the user has access to and that match the filter, if any.
      description: |
        GetPets returns all Pet instances that match the filter specified by the operation's parameters, if any.
        If no filtering criteria are provided, all Pet instances are returned. The method is safe and idempotent.
      parameters:
        - name: tags
          in: query
          description: Tags to filter Pet instances by.
          required: false
          schema:
            type: array
            items:
              type: string
      responses:
        200:
          description: Return all Pet instances the user has access to and that match the filter, as a list.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
 
</syntaxhighlight>
The following types are used:
* <code>[[OpenAPI_Specification_Schemas#Pet|Pet]]</code> type.
* <code>[[OpenAPI_Specification_Schemas#Error_Type|Error]]</code> type.
Server implementation:
<syntaxhighlight lang='go'>
func (s *PetStoreServer) GetPets(ctx echo.Context, params petstore.GetPetsParams) error {
var tags []string
ptags := params.Tags
    // ensure that tags exist, and filter our those that are empty or blank strings ...
    tags = ...
var pets []petstore.Pet
s.RLock()
defer s.RUnlock()
for _, p := range s.pets {
if len(tags) == 0 {
pets = append(pets, *p)
} else {
// filter by tags
if p.Tag != nil {
for _, t := range tags {
if *p.Tag == t {
pets = append(pets, *p)
}
}
}
}
}
resp, err := json.Marshal(pets)
if err != nil {
return err
}
_, err = ctx.Response().Write(resp)
return err
}
</syntaxhighlight>
</syntaxhighlight>
 
Invocation:
In-line schema:
<syntaxhighlight lang='bash'>
<syntaxhighlight lang='yaml'>
curl -H "Content-Type: application/json" -X GET http://localhost:30000/pets?tags=blue
responses:
  200:
    description: something
    schema:
      type: object
      properties:
        id:
          type: integer
          description: The user ID.
        username:
          type: string
          description: The user name.
</syntaxhighlight>
</syntaxhighlight>


This is an example that uses references:
==Get One Item by ID==
<syntaxhighlight lang='yaml'>
Reading resources is conventionally implemented with <code>GET</code> in REST architectures.
responses:
  200:
    description: something
    schema:
      $ref: '#/definitions/User'
...
definitions:
  User:
    type: object
    properties:
      id:
        type: integer
        description: The user ID.
      username:
        type: string
        description: The user name.
</syntaxhighlight>


"responseSchema" is sometimes used, but that seems to be deprecated.
{{Internal|REST_and_Hypermedia#GET|HTTP GET}}
===Empty Response Body===
For responses that have no body, like 204 No Content, no "schema" should be specified. This is conventionally treated as no-body response.
==Response Headers==
Responses can include custom headers, or headers that implement a protocol like [[#CORS|CORS]].
===<tt>headers</tt>===
The custom headers must be declared, under the "headers" section of the response. For OpenAPI 2.0, there is no way in Swagger to define common response headers for different response codes or different API operations. You need to define the headers for each response individually. "headers" is aA container that maps a header name to its definition. The header names are case insensitive. If a header is specified by the an extension, such as [[Amazon_API_Gateway_Extension_to_OpenAPI#x-amazon-apigateway-integration|x-amazon-apigateway-integration]], it has to be declared in the [[#headers|headers]] section for the corresponding response, otherwise a template error is generated.


OpenAPI path specification:
<syntaxhighlight lang='yaml'>
<syntaxhighlight lang='yaml'>
200:
paths:
   description: 200 response
   /pets/{id}:
  ...
    get:
  headers:
      operationId: GetPet
    Access-Control-Allow-Origin:
      summary: Get a Pet instance by ID
      type: 'string'
      description: |
    Access-Control-Allow-Methods:
        Return a single Pet instance that corresponds to the given ID, or nothing if the ID does not exist
       type: 'string'
        or the user does not have read privileges.
    Access-Control-Allow-Headers:
      parameters:
      type: 'string'
        - name: id
  schema:
          in: path
    $ref: '#/definitions/Empty'
          description: ID of Pet instance to fetch.
    originalRef: '#/definitions/Empty'
          required: true
          schema:
            type: string
            format: uuid
       responses:
        200:
          description: The Pet instance as JSON or nothing if no such Pet exists.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        404:
          description: No such ID exists.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
</syntaxhighlight>
The following types are used:
* <code>[[OpenAPI_Specification_Schemas#Pet|Pet]]</code> type.
* <code>[[OpenAPI_Specification_Schemas#Error_Type|Error]]</code> type.
Server implementation:
<syntaxhighlight lang='go'>
func (s *PetStoreServer) GetPet(ctx echo.Context, id openapi_types.UUID) error {
s.RLock()
defer s.RUnlock()
var pet *petstore.Pet
for _, p := range s.pets {
if p.ID == id {
pet = p
break
}
}
if pet == nil {
return echo.NewHTTPError(http.StatusNotFound, "no such ID: "+id.String())
}
resp, err := json.Marshal(*pet)
if err != nil {
return err
}
_, err = ctx.Response().Write(resp)
return err
}
</syntaxhighlight>
Invocation:
<syntaxhighlight lang='bash'>
local id=$1
curl -v -H "Content-Type: application/json" -X GET "http://localhost:30000/pets/${id}"
</syntaxhighlight>
</syntaxhighlight>
==Reference Object==
===<span id='TODO'></span>TODO Get Item by ID===
==CORS==
<font color=darkkhaki>If I use the <code>echo</code> server error facilities and return an <code>echo.NewHTTPError(http.StatusNotFound, "no such ID: "+id.String())</code>, then the custom error type <code>[[OpenAPI_Specification_Schemas#Error_Type|Error]]</code> is not used, even if it's declared in the operation OpenAPI definition. Reconcile that.</font>.
{{External|[https://swagger.io/docs/open-source-tools/swagger-ui/usage/cors/ CORS in Swagger]}}


More: {{Internal|Cross-Origin_Resource_Sharing|CORS}}
==Wholesale Update an Item with PUT==
==x-nullable==
Wholesale update of a resource is conventionally implemented with <code>PUT</code> in REST architectures.
Appears in automatically generated Swagger files, as such:
{{Internal|REST_and_Hypermedia#PUT|HTTP PUT}}


definitions:
==Partial Update with PATCH==
    LibraryAccount:
Partial update of a resource is conventionally implemented with <code>PATCH</code> in REST architectures.
      type: object
{{Internal|REST_and_Hypermedia#PATCH|HTTP PATCH}}
      required:
      - name
      properties:
        name:
          type: string
          '''x-nullable''': '''true'''


definitions:
==Delete an Item==
  A:
Resource deletion is conventionally implemented with <code>DELETE</code> in REST architectures.
    type: string
{{Internal|REST_and_Hypermedia#DELETE|HTTP DELETE}}
    title: A
    '''x-nullable''': '''true'''


When used for an API Gateway import, it errors out as:
OpenAPI specification:
 
<syntaxhighlight lang='yaml'>
Unable to create model for 'LibraryAccount': Invalid model specified: Validation Result: warnings : [], errors : [Invalid model schema specified. Unsupported keyword(s): ["x-nullable"]]
paths:
  /pets/{id}:
    delete:
      operationId: DeletePet
      summary: Delete the Pet instance that corresponds to the given ID.
      description: |
        Attempts to delete the Pet instance corresponding to the given ID.
      parameters:
        - name: id
          in: path
          description: ID of Pet instance to delete.
          required: true
          schema:
            type: string
            format: uuid
      responses:
        204:
          description: Standard response on successful deletion.
        404:
          description: No such ID exists.
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
</syntaxhighlight>
The following types are used:
* <code>[[OpenAPI_Specification_Schemas#Error_Type|Error]]</code> type.
Server implementation:
<syntaxhighlight lang='go'>
func (s *PetStoreServer) DeletePet(ctx echo.Context, id openapi_types.UUID) error {
s.Lock()
defer s.Unlock()
_, exists := s.pets[id]
if !exists {
return echo.NewHTTPError(http.StatusNotFound, "no such ID: "+id.String())
}
delete(s.pets, id)
return ctx.String(http.StatusNoContent, "no content")
}
</syntaxhighlight>
Invocation:
<syntaxhighlight lang='bash'>
local id=$1
curl -v -H "Content-Type: application/json" -X DELETE "http://localhost:30000/pets/${id}"
</syntaxhighlight>

Latest revision as of 03:55, 27 January 2024

Internal

Overview

The top level paths keyword introduce a map of paths, keyed by their path values:

[...]
paths:
 /a:
   [...]
 /b:
   [...]
 /c:
   [...]
[...]

Path

Each path name must start with a forward slash "/". The path is appended to the expanded URL from the server object url field in order to construct the full URL. Path templating is allowed. Each path accepts zero or more of the available operations (get, put, post, delete, options, head, patch, trace) and parameters, which is a list of parameters that are applicable for all the operations described under this path. These parameters can be overridden at operation level but cannot be removed there.

/a:
  [...]
  summary:
  description:
  get: [...] # a GET /a interface method will be generated by server code generation
  put: [...] # a PUT /a interface method will be generated by server code generation
  post: [...] # a POST /a interface method will be generated by server code generation
  delete: [...] # a DELETE /a interface method will be generated by server code generation
  options: [...]  # ...
  head: [...]
  patch: [...]
  trace: [...]
  parameters: [...]
  servers:

Server Code Generation for Path/Operation Combinations

For each path/operation combination, oapi-codegen will generate a Go "Operation /Path" handler method in the ServerInterface interface object. The name of the methods will be given by operationId value, with the first character uppercased.

Path Templating

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathTemplating

Path templating refers to the usage of curly braces {} to mark a section of a URL path as replaceable using path parameters.

Operations

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#operationObject

An operation represents a single HTTP operation on a path.

Valid operations:

  • get
  • put
  • post
  • delete
  • options
  • head
  • patch
  • trace

get|put|post|delete|options|head|patch|trace:
  summary: |
     A short description of the operation.
  operationId: GetPets
  description:  '...'
  parameters: [...]
  responses: [...]
  tags: [...]
  requestBody:
  callbacks:
  security:
  servers:
  deprecated:

operationId

A unique string, among all operations described by this API, used to identify the operation. The operationId value is case-sensitive. Tools and libraries may use operationId to uniquely identify an operation, therefore, it is recommended to follow common programming naming conventions.

oapi-codegen uses operationId as a base for a various function and struct names in client and server generated code. All names get their first character upper-cased, making them exported, regardless of whether the first character of the operationId is lower or upper case. For:

paths:
  /pets:
    get:
      operationId: GetPets
      [...]

oapi-codegen generates:

[...]

// The interface specification for the client above.
type ClientInterface interface {
	// GetPets request
	GetPets(ctx context.Context, params *GetPetsParams, reqEditors ...RequestEditorFn) (*http.Response, error)
}

[...]

// ServerInterface represents all server handlers.
type ServerInterface interface {
	// (GET /pets)
	GetPets(ctx echo.Context, params GetPetsParams) error
}

[...]

summary

Surfaces in the generated code, as the generated server interface method comment.

description

responses

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responses-object

The responses field is required and lists all possible HTTP responses that may result from executing this operation.

Response

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#responseObject

The element must contain at least one response code. The definition is not expected to cover all possible HTTP response codes, because they may not be known in advance. However, the definition should cover a successful operation response and any known errors. The default map key may be used as a default response object for all HTTP codes that are not covered individually in the definition.

paths:
  /pets:
    get:
      [...]
      responses:
        200:
          description: Return all the pets the user has access to, as a list.
          headers: [...]
          links: [...]
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

An empty response:

paths:
  /a:
    get:
      [...]
      responses:
        200:
          schema:
            $ref: '#/components/schemas/Empty'

The Empty type is declared in the /components/schemas as such:

Empty

headers

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#headerObject

The header object follows the structure of a parameter object, with the exceptions that name must not be specified, it is given in the corresponding headers map, and in must not be specified, it is implicitly in header. headers is a container that maps a header name to its definition. The header names are case insensitive. If a header is specified by the an extension, such as x-amazon-apigateway-integration, it has to be declared in the headers section for the corresponding response, otherwise a template error is generated. Responses can include custom headers, or headers that implement a protocol like CORS.

200:
  [...]
  headers:
    Access-Control-Allow-Origin:
      description: some description
      schema:
        type: string
    Access-Control-Allow-Methods:
      description: some description
      schema:
        type: string
    Access-Control-Allow-Headers:
      description: some description
      schema:
        type: string

requestBody

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#request-body-object

Also see:

REST Request Body

tags

Each operation can be annotated with a list of tags. Tagged operations may be handled differently by tools and libraries. Optionally, each tag can get a description and an externalDocs in the global tags section on the root level. The tag names here should match those used in operations. The tag order in the global tags section also controls the default sorting in the UI. It is possible to use a tag at operation level even if it is not specified on the root level.

tags:
  - name: tag-a
    description: Something that would shed light on tag-a semantics
    externalDocs:
      url: https://example.com/my-docs/tag-a.html
paths:
  /a:
    get:
      tags:
        - tag-a
        - other-tag

Parameters

https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameterObject

A unique parameter is defined by a combination of its name, defined as value of the name field, and its location, defined as value of the in field. The name value is required and case sensitive. There are four possible parameter locations: "query", "header", "path", "cookie". An operation accepts multiple parameters, which should be specified as an array.

get:
  [...]
  parameters:
    - name: Color
      in: path|query|header|cookie
      description:
      required: true|false
      style: form
      schema: [...]
      deprecated: true|false
      allowEmptyValue: true|false
    - [...]

Parameter Locations

Path Parameters

A path parameter is declared as in: path in the OpenAPI specification file, and is a URL fragment at the left side of the question mark in the URL. For "path" parameters, the parameter name must correspond to a template expression occurring in the path field. The parameter value is actually part of the operation's URL. Also, the required property is required and the value must be true.

 /query/{id}

paths:
 /query/{id}:
   get:
     - name: id
       in: path
       required: true
       [...]

Also see:

REST Path Parameters

Query Parameters

A query parameter is declared as in: query in the OpenAPI specification file, and it is an URL fragment that follows the question mark in the full URL.

allowEmptyValue field is valid only for query parameters and allows sending a parameter with an empty value. The default value is false. Use of this property is not recommended and it is likely to be removed in a later revision.

Also see:

REST Query Parameters

Header Parameters

Header parameters are key value pairs that can be used to configure the behavior of the API.

Also see:

REST Request Headers

Cookie Parameters

Parameter Schema

paths:
  /pets:
    get:
      parameters:
        - name: tags
          [...]
          schema:
            type: array
            items:
              type: string

Operation Declaration and Implementation Examples

The server code generation the following examples work in top of is done with:

oapi-codegen

Create a Resource Instance

Creation of new resources is conventionally implemented with POST in REST architectures.

HTTP POST

OpenAPI path specification:

paths:
  /pets:
    post:
      operationId: CreatePet
      summary: Create a new Pet instance.
      description: |
        CreatePet creates a new Pet instance, expecting all required state as arguments. 
        It generates an unique ID. The method is NOT idempotent.
      requestBody:
        description: The state of the Pet to be added to the store.
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PetPayload'
      responses:
        201:
          description: The state of a newly create instance, including the new ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

The following types are used:

Server implementation:

func (s *PetStoreServer) CreatePet(ctx echo.Context) error {
	var petPayload petstore.PetPayload
	err := json.NewDecoder(ctx.Request().Body).Decode(&petPayload)
	if err != nil {
		return err
	}
	// create and store the pet, then return the result, the ID will be generated internally by NewPet()
	p := petstore.NewPet(petPayload)
	s.Lock()
	defer s.Unlock()
	s.pets[p.ID] = p
	resp, err := json.Marshal(p)
	if err != nil {
		return err
	}
	_, err = ctx.Response().Write(resp)
	return err
}

Invocation:

curl -H "Content-Type: application/json" -X POST -d '{"name":"Fido", "age":2, "tag":"blue"}' http://localhost:30000/pets

TODO Create

The appropriate response should be 201. See HTTP 201 and the "Location" header may contain the URL of the new resource, see:

HTTP POST

Get All Items as a JSON Array

Reading resources is conventionally implemented with GET in REST architectures.

HTTP GET

OpenAPI path specification:

paths:
  /pets:
    get:
      operationId: GetPets
      summary: Get all Pet instances the user has access to and that match the filter, if any.
      description: |
        GetPets returns all Pet instances that match the filter specified by the operation's parameters, if any. 
        If no filtering criteria are provided, all Pet instances are returned. The method is safe and idempotent.
      parameters:
        - name: tags
          in: query
          description: Tags to filter Pet instances by.
          required: false
          schema:
            type: array
            items:
              type: string
      responses:
        200:
          description: Return all Pet instances the user has access to and that match the filter, as a list.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

The following types are used:

Server implementation:

func (s *PetStoreServer) GetPets(ctx echo.Context, params petstore.GetPetsParams) error {
	var tags []string
	ptags := params.Tags
    // ensure that tags exist, and filter our those that are empty or blank strings ...
    tags = ...
	var pets []petstore.Pet
	s.RLock()
	defer s.RUnlock()
	for _, p := range s.pets {
		if len(tags) == 0 {
			pets = append(pets, *p)
		} else {
			// filter by tags
			if p.Tag != nil {
				for _, t := range tags {
					if *p.Tag == t {
						pets = append(pets, *p)
					}
				}
			}
		}
	}
	resp, err := json.Marshal(pets)
	if err != nil {
		return err
	}
	_, err = ctx.Response().Write(resp)
	return err
}

Invocation:

curl -H "Content-Type: application/json" -X GET http://localhost:30000/pets?tags=blue

Get One Item by ID

Reading resources is conventionally implemented with GET in REST architectures.

HTTP GET

OpenAPI path specification:

paths:
  /pets/{id}:
    get:
      operationId: GetPet
      summary: Get a Pet instance by ID
      description: |
        Return a single Pet instance that corresponds to the given ID, or nothing if the ID does not exist
        or the user does not have read privileges.
      parameters:
        - name: id
          in: path
          description: ID of Pet instance to fetch.
          required: true
          schema:
            type: string
            format: uuid
      responses:
        200:
          description: The Pet instance as JSON or nothing if no such Pet exists.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        404:
          description: No such ID exists.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

The following types are used:

Server implementation:

func (s *PetStoreServer) GetPet(ctx echo.Context, id openapi_types.UUID) error {
	s.RLock()
	defer s.RUnlock()
	var pet *petstore.Pet
	for _, p := range s.pets {
		if p.ID == id {
			pet = p
			break
		}
	}
	if pet == nil {
		return echo.NewHTTPError(http.StatusNotFound, "no such ID: "+id.String())
	}
	resp, err := json.Marshal(*pet)
	if err != nil {
		return err
	}
	_, err = ctx.Response().Write(resp)
	return err
}

Invocation:

local id=$1
curl -v -H "Content-Type: application/json" -X GET "http://localhost:30000/pets/${id}"

TODO Get Item by ID

If I use the echo server error facilities and return an echo.NewHTTPError(http.StatusNotFound, "no such ID: "+id.String()), then the custom error type Error is not used, even if it's declared in the operation OpenAPI definition. Reconcile that..

Wholesale Update an Item with PUT

Wholesale update of a resource is conventionally implemented with PUT in REST architectures.

HTTP PUT

Partial Update with PATCH

Partial update of a resource is conventionally implemented with PATCH in REST architectures.

HTTP PATCH

Delete an Item

Resource deletion is conventionally implemented with DELETE in REST architectures.

HTTP DELETE

OpenAPI specification:

paths:
  /pets/{id}:
    delete:
      operationId: DeletePet
      summary: Delete the Pet instance that corresponds to the given ID.
      description: |
        Attempts to delete the Pet instance corresponding to the given ID.
      parameters:
        - name: id
          in: path
          description: ID of Pet instance to delete.
          required: true
          schema:
            type: string
            format: uuid
      responses:
        204:
          description: Standard response on successful deletion.
        404:
          description: No such ID exists.
        default:
          description: Unexpected error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

The following types are used:

Server implementation:

func (s *PetStoreServer) DeletePet(ctx echo.Context, id openapi_types.UUID) error {
	s.Lock()
	defer s.Unlock()
	_, exists := s.pets[id]
	if !exists {
		return echo.NewHTTPError(http.StatusNotFound, "no such ID: "+id.String())
	}
	delete(s.pets, id)
	return ctx.String(http.StatusNoContent, "no content")
}

Invocation:

local id=$1
curl -v -H "Content-Type: application/json" -X DELETE "http://localhost:30000/pets/${id}"