-
Notifications
You must be signed in to change notification settings - Fork 69
Tools or Specs that can help define API workflows #10
-
We may not want to reinvent the wheel, so let's share some thoughts on specifications or existing mechanisms that warrant some discussion and considerations as part of this SIG.
Examples:
- Gherkin
- UML
- API Design Systems I also see potential to pivot from proposed spec and leverage something similar for describing flows
Also what learnings can we take from the likes of
- WS-CDL
- XPDL
- BPMN
- WS-BPEL
- BPEL for REST
- JOpera
- RESTalk
etc.
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 3 comments 1 reply
-
The schemathesis test frameworks already use openAPI links to model dependencies between calls. We talked last time about this possibility.
This tool has already a kind of workflow engine based on this rule based state engine
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi! Schemathesis author here.
FWIW, I got a few thoughts about Open API links, described here. They are mostly about the limitations for data generation I faced before (especially on runtime expressions). I hope, that it might be helpful here :)
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Rough example of extension to describe workflows within an OpenAPI spec as proposed by @aduminuc during our meeting on Nov 10th. You can refer to this deck for additional context on the example proposal.
In essence, the proposal introduces the concept of Procedures (name not important for now) which define a set of actions over one or more APIs to achieve an objective.
A procedure defines:
- A set of input parameters, similarly to what an operation does
- An ordered list of steps, where each step represents a call to an operation or to another procedure.
- A set of outputs
Each step describes:
- Which OpenAPI operation or extension procedure to call
- How to populate the input parameters
- Defines success conditions
- What to do on failure events
The following described two procedures (a.k.a workflows), the first for logging in and retrieving user details and the second for purchasing a pet
x-worflow-sig:
procedures:
userloginandretrieve:
summary: log in and retrieve a user
procedureID: userLoginAndRetrieve
description: Log in a user with a given username and password and then retrieve user details.
parameters:
- name: username
description: The user name for login
required: true
schema:
type: string
- name: password
description: The password for login in clear text
required: true
schema:
type: string
steps:
- stepId: loginStep
operationId: loginUser
description: Login user
parameters:
username: $parameters.username
password: $parameters.password
success:
- $response.code == 200
- stepId: getUserStep
oprationRef: https://petstore3.swagger.io/api/v3/openapi.json#/paths/~1user~1{username}/get
parameters:
username: $parameters.username
success:
- $response.code == 200
outputs:
user: $steps.getUserStep.responses.200
petpurchase:
summary: purchase a pet by name
procedureID: purchasePetByName
description: A procedure to pick and purchase a pet knowing its name
parameters:
- name: petName
description: Name of pet to purchase
required: true
schema:
type: string
- name: username
in: query
description: The user name for login
required: true
schema:
type: string
- name: password
in: query
description: The password for login in clear text
required: true
schema:
type: string
steps:
- stepId: getUserStep
procedureId: userLoginAndRetrieve
parameters:
username: $parameters.username
password: $parameters.password
success:
- $outputs.user.address is not None
onFailure: exit
- stepId: getPetStep
description: retrieve a Pet by Name
operationID: getPetByName
parameters:
petName: $parameters.petName
success:
- $response.code == 200
- $response.200.status == 'available'
onFailure: exit
- stepId: purchaseStep
description: place order
operationId: placeOrder
requestBody:
petId: $steps.getPetStep.responses.200.petID
address: $steps.getUserStep.outputs.user.address
success:
- $response.code == 200
- $response.200.status == "approved"
onFailure: retry
ouputs:
order: $steps.purchaseStep.responses.200
Below is the Petstore OpenAPI specification with the additional extension at the end.
openapi: 3.0.2
info:
title: Swagger Petstore - OpenAPI 3.0
description: |-
This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
You can now help us improve the API whether it's by making changes to the definition itself or to the code.
That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
Some useful links:
- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
termsOfService: http://swagger.io/terms/
contact:
email: apiteam@swagger.io
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.6
externalDocs:
description: Find out more about Swagger
url: http://swagger.io
servers:
- url: /api/v3
tags:
- name: pet
description: Everything about your Pets
externalDocs:
description: Find out more
url: http://swagger.io
- name: store
description: Operations about user
- name: user
description: Access to Petstore orders
externalDocs:
description: Find out more about our store
url: http://swagger.io
paths:
/pet:
put:
tags:
- pet
summary: Update an existing pet
description: Update an existing pet by Id
operationId: updatePet
requestBody:
description: Update an existent pet in the store
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
required: true
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
links:
GetPetById:
operationId: getPetById
parameters:
petId : '#response.body#/id'
description: ID returned by this method can be used to retrieve the Pet
'400':
description: Invalid ID supplied
'404':
description: Pet not found
'405':
description: Validation exception
security:
- petstore_auth:
- write:pets
- read:pets
post:
tags:
- pet
summary: Add a new pet to the store
description: Add a new pet to the store
operationId: addPet
requestBody:
description: Create a new pet in the store
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
required: true
responses:
'200':
description: Successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/json:
schema:
$ref: '#/components/schemas/Pet'
'405':
description: Invalid input
security:
- petstore_auth:
- write:pets
- read:pets
/pet/findByName/{petName}:
get:
tags:
- pet
summary: Finds a pet by name
description: Find a pet by name
operationId: findPetByName
parameters:
- name: petName
in: path
description: Name of pet to return
required: true
schema:
type: string
responses:
'200':
description: successful operation
content:
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid status value
security:
- petstore_auth:
- write:pets
- read:pets
/pet/{petId}:
get:
tags:
- pet
summary: Find pet by ID
description: Returns a single pet
operationId: getPetById
parameters:
- name: petId
in: path
description: ID of pet to return
required: true
schema:
type: integer
format: int64
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/json:
schema:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid ID supplied
'404':
description: Pet not found
security:
- api_key: []
- petstore_auth:
- write:pets
- read:pets
post:
tags:
- pet
summary: Updates a pet in the store with form data
description: ''
operationId: updatePetWithForm
parameters:
- name: petId
in: path
description: ID of pet that needs to be updated
required: true
schema:
type: integer
format: int64
- name: name
in: query
description: Name of pet that needs to be updated
schema:
type: string
- name: status
in: query
description: Status of pet that needs to be updated
schema:
type: string
responses:
'405':
description: Invalid input
security:
- petstore_auth:
- write:pets
- read:pets
delete:
tags:
- pet
summary: Deletes a pet
description: ''
operationId: deletePet
parameters:
- name: api_key
in: header
description: ''
required: false
schema:
type: string
- name: petId
in: path
description: Pet id to delete
required: true
schema:
type: integer
format: int64
responses:
'400':
description: Invalid pet value
security:
- petstore_auth:
- write:pets
- read:pets
/store/order:
post:
tags:
- store
summary: Place an order for a pet
description: Place a new order in the store
operationId: placeOrder
parameters:
- name: petId
in: query
description: ID of pet to return
required: true
schema:
type: integer
format: int64
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
application/xml:
schema:
$ref: '#/components/schemas/Order'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/Order'
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
'405':
description: Invalid input
/store/order/{orderId}:
get:
tags:
- store
summary: Find purchase order by ID
description: For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
operationId: getOrderById
parameters:
- name: orderId
in: path
description: ID of order that needs to be fetched
required: true
schema:
type: integer
format: int64
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Order'
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
description: Invalid ID supplied
'404':
description: Order not found
delete:
tags:
- store
summary: Delete purchase order by ID
description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
operationId: deleteOrder
parameters:
- name: orderId
in: path
description: ID of the order that needs to be deleted
required: true
schema:
type: integer
format: int64
responses:
'400':
description: Invalid ID supplied
'404':
description: Order not found
/user:
post:
tags:
- user
summary: Create user
description: This can only be done by the logged in user.
operationId: createUser
requestBody:
description: Created user object
content:
application/json:
schema:
$ref: '#/components/schemas/User'
application/xml:
schema:
$ref: '#/components/schemas/User'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/User'
responses:
default:
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/User'
application/xml:
schema:
$ref: '#/components/schemas/User'
/user/login:
get:
tags:
- user
summary: Logs user into the system
description: ''
operationId: loginUser
parameters:
- name: username
in: query
description: The user name for login
required: false
schema:
type: string
- name: password
in: query
description: The password for login in clear text
required: false
schema:
type: string
responses:
'200':
description: successful operation
headers:
X-Rate-Limit:
description: calls per hour allowed by the user
schema:
type: integer
format: int32
X-Expires-After:
description: date in UTC when token expires
schema:
type: string
format: date-time
content:
application/xml:
schema:
type: string
application/json:
schema:
type: string
'400':
description: Invalid username/password supplied
/user/logout:
get:
tags:
- user
summary: Logs out current logged in user session
description: ''
operationId: logoutUser
parameters: []
responses:
default:
description: successful operation
/user/{username}:
get:
tags:
- user
summary: Get user by user name
description: ''
operationId: getUserByName
parameters:
- name: username
in: path
description: 'The name that needs to be fetched. Use user1 for testing. '
required: true
schema:
type: string
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/User'
application/json:
schema:
$ref: '#/components/schemas/User'
'400':
description: Invalid username supplied
'404':
description: User not found
put:
tags:
- user
summary: Update user
description: This can only be done by the logged in user.
operationId: updateUser
parameters:
- name: username
in: path
description: name that need to be deleted
required: true
schema:
type: string
requestBody:
description: Update an existent user in the store
content:
application/json:
schema:
$ref: '#/components/schemas/User'
application/xml:
schema:
$ref: '#/components/schemas/User'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/User'
responses:
default:
description: successful operation
delete:
tags:
- user
summary: Delete user
description: This can only be done by the logged in user.
operationId: deleteUser
parameters:
- name: username
in: path
description: The name that needs to be deleted
required: true
schema:
type: string
responses:
'400':
description: Invalid username supplied
'404':
description: User not found
components:
schemas:
OrderCreate:
type: object
properties:
petId:
type: integer
format: int64
example: 198772
address:
$ref: '#/components/schemas/Address'
xml:
name: order
Order:
type: object
properties:
id:
type: integer
format: int64
example: 10
petId:
type: integer
format: int64
example: 198772
address:
$ref: '#/components/schemas/Address'
shipDate:
type: string
format: date-time
status:
type: string
description: Order Status
example: approved
enum:
- placed
- approved
- delivered
complete:
type: boolean
xml:
name: order
Address:
type: object
properties:
street:
type: string
example: 437 Lytton
city:
type: string
example: Palo Alto
state:
type: string
example: CA
zip:
type: string
example: '94301'
xml:
name: address
Category:
type: object
properties:
id:
type: integer
format: int64
example: 1
name:
type: string
example: Dogs
xml:
name: category
User:
type: object
properties:
id:
type: integer
format: int64
example: 10
username:
type: string
example: theUser
firstName:
type: string
example: John
lastName:
type: string
example: James
email:
type: string
example: john@email.com
password:
type: string
example: '12345'
phone:
type: string
example: '12345'
userStatus:
type: integer
description: User Status
format: int32
example: 1
address:
$ref: '#/components/schemas/Address'
xml:
name: user
Tag:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
xml:
name: tag
Pet:
required:
- name
- photoUrls
type: object
properties:
id:
type: integer
format: int64
example: 10
name:
type: string
example: doggie
category:
$ref: '#/components/schemas/Category'
photoUrls:
type: array
xml:
wrapped: true
items:
type: string
xml:
name: photoUrl
tags:
type: array
xml:
wrapped: true
items:
$ref: '#/components/schemas/Tag'
status:
type: string
description: pet status in the store
enum:
- available
- pending
- sold
xml:
name: pet
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: https://petstore3.swagger.io/oauth/authorize
scopes:
write:pets: modify pets in your account
read:pets: read your pets
api_key:
type: apiKey
name: api_key
in: header
x-worflow-sig:
procedures:
userloginandretrieve:
summary: log in and retrieve a user
procedureID: userLoginAndRetrieve
description: Log in a user with a given username and password and then retrieve user details.
parameters:
- name: username
description: The user name for login
required: true
schema:
type: string
- name: password
description: The password for login in clear text
required: true
schema:
type: string
steps:
- stepId: loginStep
operationId: loginUser
description: Login user
parameters:
username: $parameters.username
password: $parameters.password
success:
- $response.code == 200
- stepId: getUserStep
oprationRef: https://petstore3.swagger.io/api/v3/openapi.json#/paths/~1user~1{username}/get
parameters:
username: $parameters.username
success:
- $response.code == 200
outputs:
user: $steps.getUserStep.responses.200
petpurchase:
summary: purchase a pet by name
procedureID: purchasePetByName
description: A procedure to pick and purchase a pet knowing its name
parameters:
- name: petName
description: Name of pet to purchase
required: true
schema:
type: string
- name: username
in: query
description: The user name for login
required: true
schema:
type: string
- name: password
in: query
description: The password for login in clear text
required: true
schema:
type: string
steps:
- stepId: getUserStep
procedureId: userLoginAndRetrieve
parameters:
username: $parameters.username
password: $parameters.password
success:
- $outputs.user.address is not None
onFailure: exit
- stepId: getPetStep
description: retrieve a Pet by Name
operationID: getPetByName
parameters:
petName: $parameters.petName
success:
- $response.code == 200
- $response.200.status == 'available'
onFailure: exit
- stepId: purchaseStep
description: place order
operationId: placeOrder
requestBody:
petId: $steps.getPetStep.responses.200.petID
address: $steps.getUserStep.outputs.user.address
success:
- $response.code == 200
- $response.200.status == "approved"
onFailure: retry
ouputs:
order: $steps.purchaseStep.responses.200
Beta Was this translation helpful? Give feedback.
All reactions
-
Here is an attempt at representing a sequence of calls that make up an OpenID Connect flow, specifically an Authorization code flow with a Pushed Authorization Request. I have tried to make it a accurate as possible but there may be a few errors here an there. This is not to be used as the basis for OIDC documentation! Also there are probably things that are in the existing OAI spec that could help with this example but I am not yet expert in OAI.
I have taken a lot of inspiration from the contribution above but a number of aspects either didn't quite work or just didn't feel right in the context of the example presented. Some of these issues are addressed with changes and others I have not come up with a reasonable idea for yet.
Also as per comment above names of elements are not terribly important for now.
Things adjusted between the petstore example and this:
- I added a new element called participants - this is to capture the list of source and destination and allow for additional attributes to be documented - I have not come up with additional participant attributes yet
- I renamed "procedures.parameters" to "procedure.variables" - it appears to me that this will reduce confusion about
parametersof a single call withvariablesneeded for aprocedure - The variables is also not a complete list of all parameters used in all the calls, just what is needed as input to a procedure
- I am not feeling comfortable with structured objects being defined inside "procedure.variables" but I have done a couple there and one inside "step.xxx.parameters" to compare and contrast
- There may well be multiple requestBody elements needed for a
procedureso I have given the two needed in this example specific names (this may not be needed if we end up defining them inside each step they are needed within) sourceanddestinationwithin eachstepmatching members of the list ofparticipants. In this example there are two sources- In the step parameters I have added some schema content and a key called
valuewhere static values are used for a given procedure step
Things I am concerned about but have not addressed
- The Authorization endpoint call was not represented within OAI as it is from a user agent and a successful response is a 302 redirect
- The client assertion paramer gives a particular challenge because there are two uses of it in this procedure and they have different content, It is in the form of a JWS and it must contain a unique
jtivalue and an accurateiatvalue (issued at) and then it must be signed. - It feels likely that further functions will be needed. In this example there appears to be a need for
random,timeandsign - In the list of steps it might be useful to add an index number - not sure
AuthenticationAPI-v3.0.0-procedure-PAR&OIDCalpha2.yaml.txt
apparently not allowed to upload .yaml files here
Beta Was this translation helpful? Give feedback.