Writing a Swagger / OpenAPI schema for the YesNo API
24 May 2020
Table of Contents
In response to my “Salesforce Flow External Services” tutorial, reader “AMZ Cloud” asked, “How did you generate the ‘Service Schema Complete JSON’?”
The quick answer is: “by hand. With a lot of guessing and making mistakes.”
Learning YesNo’s API thoroughly
The first thing I did was visit YesNo’s API documentation at https://yesno.wtf/#api.
Having a little experience with HTTP-based APIs, I interpreted the documentation to mean that if I made an HTTP request using the “GET” method to one of the following four URLs:
https://yesno.wtf/api
https://yesno.wtf/api?force=yes
https://yesno.wtf/api?force=no
https://yesno.wtf/api?force=maybe
…then I would receive an HTTP response whose “body” was a concise piece of plaintext formatted in the JSON punctuation standard, indicating values for 3 “keys”:
- “answer”
- (always a values of “
yes
”, “no
”, or “maybe
” – randomized if I visited the first URL possibility; fixed if I visited any of the “force=
” URL possibilities)
- (always a values of “
- “forced”
- (always a value of “
false
” if I visited the first URL possibility; always a value of “true
” if I visited any of the “force=
” URL possibilities)
- (always a value of “
- “image”
- (always a URL to a file starting in
https://yesno.wtf/
and ending in.gif
)
- (always a URL to a file starting in
Now that I personally understood everything about YesNo that I could possibly want to explain to my Flow, I needed to figure out how to to write it down according to “Swagger” / “OpenAPI 2.0” standards for “schemas.”
What is a schema?
- Q: What’s a schema?
- A: In this context, a “schema” is a file that:
- is plain text
- is formatted in a punctuation standard that makes it easy for a computer to read and interpret structure from (e.g. JSON or YAML)
- describes where a given HTTP “REST”-flavored API lives on the internet
- describes what HTTP requests you’re allowed to make to the API’s “endpoints”
- describes what kinds of HTTP responses you should expect in return from various requests to the API’s endpoints
YAML
To write my schema, I used online editor tools provided by SmartBear.
One thing to know about SmartBear’s editor tools is that they make you write your “schema” in a punctuation standard called “YAML.” We haven’t talked about YAML on the site before. Luckily, it’s not too difficult to guess your way around.
- Like CSV and XML and JSON, YAML is a punctuation standard for formatting the context of plain-text files so that computers can interpret the contents of the file as “data” according to a human’s intent.
- YAML is closer to XML and JSON than it is to CSV, because like XML and JSON, it’s optimized for holding “list-of-list”-shaped data. Therefore, just as XML and JSON are pretty interchangeable with each other, conceptually, YAML is pretty interchangeable with both of them – so much so that we’ll finish this tutorial by clicking a “Convert and save as JSON” button in our schema editor.
- Unlike XML or JSON, though, whitespacing and line breaks are part of the YAML punctuation standard.
Defining a schema in SwaggerHub
[[[TO DO:]]] WRITE ME!
Set up an account
[[[TO DO:]]] WRITE ME
Create a new Schema
From within your SwaggerHub “hub” at https://app.swaggerhub.com/home, click “Create New API.”
I believe it was somewhere in the middle of the page before I had created any;
In the dialog box that pops up, enter the following and click Save
- OpenAPI version:
2.0
- Template:
None
- Name:
YesNo
- (or whatever makes sense to you for recordkeeping within your “hub” of schemas stored in SmartBear’s service – you’ll see in subsequent screenshots that I had to make it “
YesNoTutorial
” because I’d already used up “YesNo
” on a finished product that I hyperlinked to in other discussions)
- (or whatever makes sense to you for recordkeeping within your “hub” of schemas stored in SmartBear’s service – you’ll see in subsequent screenshots that I had to make it “
- Version:
1.0.0
- (or whatever makes sense to you – this will become part of the data within your schema)
- Title:
YesNo
- (or whatever makes sense to you – this will become part of the data within your schema)
- Description:
This is a sample YesNo server.
- (or whatever makes sense to you – this will become part of the data within your schema)
Ta-da: the beginnings of your first schema
You will be taken to a URL of the format https://app.swaggerhub.com/apis/YOUR_SWAGGERHUB_USERNAME/YOUR_PROJECT_NAME/YOUR_VERSION_NUMBER
, and the code editor will read as follows:
swagger: '2.0'
info:
version: '1.0.0'
title: 'YesNo'
description: 'This is a sample YesNo server.'
paths: {}
# Added by API Auto Mocking Plugin
host: virtserver.swaggerhub.com
basePath: /kswaggerhub/YesNoTutorial/1.0.0
schemes:
- https
See how “version” and “title” and “description” are considered sub-properties of a key called “info” in the second line of the YAML-formatted file? As promised, the values you typed into the “new schema” window are here. Edit them here and click “Save” above the central code-editing panel if you’ve changed your mind about what you’d like them to say. (Although note that editing the version number will change your “Save” button into a “Create new version” button, since SwaggerHub has to generate a new editing URL for you when you change the version number.) Note that if you change these, your previewer at right will keep up with the changes you make in the center panel.
SwaggerHub also added a few extra pieces of data to the schema for us:
- It gave the file a “swagger” property of
2.0
, as specified in “OpenAPI version” while creating the file - It gave the file a “schemes” property containing a 1-item list of acceptable internet communication standards – in this case, just “secure HTTP,” or
https
. That’s fine – YesNo’s URL includes an “s” in the “https://...
,” so let’s stick with that. - It gave the file “host” and “basePath” properties saying where on the internet the API “lives.”
- We’ll have to update this to tell it that the host is
yesno.wtf
, notvirtserver.swaggerhub.com
and get rid of basepath altogether – but at the last minute, after we’re done testing, because SwaggerHub will just keep un-doing our work every time we save until then.
- We’ll have to update this to tell it that the host is
Add “/api
” as an “endpoint” in “tags”
YesNo only has one “endpoint” in its whole API – the URL that ends in “/api
” – so we’ll only have one “endpoint” to specify in a part of the Swagger / OpenAPI 2.0 standard under a property of the document called “tags”.
Copy and paste the following code into the bottom of your central YAML editing panel and click the blue “Save” button above the panel (it will turn gray once you’ve saved your work):
tags:
- name: api
description: The only endpoint YesNo offers
externalDocs:
description: Find out more
url: 'https://yesno.wtf/#api'
Define a “YesNoMaybe” as shorthand
We have work to do further specifying how “/api
” works over at YesNo, but before we do, we’re going to take a moment to specify what kind of structure to expect in the “response body” that arises from making a request to https://yesno.wtf/api
.
We’ll call this specification YesNoMaybe
, which will serve as a nice shorthand when we get around to specifying how “/api
” works.
Copy and paste the following text into the end of your schema, making sure that your cursor was at the far left side of the editor, not indented, when you do, and save your work:
definitions:
YesNoMaybe:
type: object
required:
- answer
- forced
- image
properties:
answer:
type: string
description: 'yes, no, or maybe'
example: 'yes'
enum:
- 'yes'
- 'no'
- 'maybe'
forced:
type: boolean
description: Did you force the answer with a query parameter?
example: false
image:
type: string
description: The URL to a random GIF of a celebrity expressing the answer
example: 'https://yesno.wtf/assets/no/13-755222c98795431aa2e7d453ab1e75a1.gif'
As you can see, our YAML-formatted “schema” file now has a new property named “definitions”, which contains a 1-item list of sub-properties.
That sub-property is called “YesNoMaybe
” because I thought that’d make a good name.
“YesNoMaybe
” itself has 3 sub-properties, called “type”, “required”, and “properties”.
We set the value of the property “type” gets set to “object
” to indicate that the shorthand “YesNoMaybe
” is shorthand for structured data. (We’ll use “required
” and “properties
” to indicate just how it’s structured.)
Remember, HTTP requests to https://yesno.wtf/api
and its variants all return an HTTP response whose “body” that is a concise piece of plaintext formatted in the JSON punctuation standard, indicating values for 3 “keys”:
- “answer”
- (always a values of “
yes
”, “no
”, or “maybe
” – randomized if I visited the first URL possibility; fixed if I visited any of the “force=
” URL possibilities)
- (always a values of “
- “forced”
- (always a value of “
false
” if I visited the first URL possibility; always a value of “true
” if I visited any of the “force=
” URL possibilities)
- (always a value of “
- “image”
- (always a URL to a file starting in
https://yesno.wtf/
and ending in.gif
)
- (always a URL to a file starting in
The fact that YesNo’s API always includes each of these 3 “keys” in the JSON-formatted body of its response means that we can tell our “schema” that they are to be expected. Hence listing them under “required”.
Finally, as sub-properties to “properties”, we’ll list 3 more things called “answer
,” “forced
”, and “image
.”
Each of these will have 3 sub-properties of “type” (used by computers like Salesforce Flow to determine what “data type” to interpret a piece of the response as – “string” is a programmer-ey way of saying “plain text”) “description” (free-form hints for human eyes) and “example” (also geared at human eyes). “answer
” will also have a 4th sub-property of “enum” to specify that its possible responses are limited to “yes
”, “no
”, and “maybe
” (potentially used by computers like Salesforce Flow, if a user interface wanted to get fancy and render picklists for data entry and such).
Although “forced” has a limited set of possible values, it doesn’t need an “enum” sub-property because “true” and “false” as the only 2 options are implied by saying its data type is “Boolean.”
Note that in the “example” and “enum” properties, “string”-typed values have little single quotes ('
) around them. Make sure you get that right when typing up your schema.
Flesh out the “/api
” as an “endpoint” in “paths”
Now that we’ve defined a “YesNoMaybe
,” let’s finish explaining with our schema how “https://yesno.wtf/api
” works.
Personally, I like to have my “paths” block of my schema between my “tags” and “definitions block, so put an empty line between the last line of the “tags” block (“url: 'https://yesno.wtf/#api'
“) of YAML-formatted text and the first line of the “**definitions**
” block of YAML-formatted text, making sure your cursor is at left, not indented.
Copy and paste in the following code:
paths:
/api:
get:
tags:
- api
summary: 'Seek a random yes, no, or maybe'
operationId: seekAnswer
produces:
- application/json
parameters:
- name: force
in: query
description: Use this to force one of the 3 valid answers
required: false
type: string
enum:
- 'yes'
- 'no'
- maybe
responses:
'200':
description: successful operation
schema:
$ref: '#/definitions/YesNoMaybe'
If you get a “duplicated mapping key” error at the bottom of your editor in a red box, delete the line of YAML-formatted text near the top that SwaggerHub had put in between “description: 'This is a sample YesNo server.'
and # Added by API Auto Mocking Plugin
that reads:
paths: {}
(Sorry, I forgot to take that out earlier.)
Save your work.
As you can see, our YAML-formatted “schema” file now has a new property named “paths”, which contains a 1-item list of sub-properties.
That sub-property is called “/api
” because that’s the part of the URL to the API that comes between the “base path” (in this case, https://yesno.wtf
) and the optional question mark indicating the beginning of “query parameters.”
“/api
” itself has just 1 sub-property, called “get
”, because the “https://yesno.wtf/api
” endpoint of the YesNo API only responds to the “GET” HTTP method. We don’t need to bother explaining what the API might do in response to any other HTTP methods.
“get
” has 6 sub-properties:
- tags
- The cross-reference to our “
api
” tag that we defined earlier tells SwaggerHub’s preview panel at right to make sure that it associates this definition of the behavior of “/api
”GET
operations with the header we built earlier and labeled, “The only endpoint YesNo offers” and displays it underneath that label. - I’m not sure yet exactly why “
api
is a 1-item list under “tags” rather than a simple single value like you see after “summary.” But it is.
- The cross-reference to our “
- summary
- Here we type some human-readable text, like
'Seek a random yes, no, or maybe'
, to tell humans what to expect when performing aGET
HTTP request againsthttps://yesno.wtf/api
.
- Here we type some human-readable text, like
- operationId
- We can put anything we want here. It will show up in Flow when we build a Flow Action. I liked the phrase “
seekAnswer
.”
- We can put anything we want here. It will show up in Flow when we build a Flow Action. I liked the phrase “
- produces
- We know (because we’ve studied JSON and recognize it on sight when reading the YesNo API documentation) that the entire body of an HTTP response to a
GET
HTTP request againsthttps://yesno.wtf/api
is formatted according to the JSON punctuation standard. The code to indicate that in this case is “application/json
”. - I’m not sure yet exactly why “
application/json
is a 1-item list under “produces” rather than a simple single value like you see after “summary.” But it is.
- We know (because we’ve studied JSON and recognize it on sight when reading the YesNo API documentation) that the entire body of an HTTP response to a
- parameters
- Let’s come back to this in a minute. It’s long.
- responses
- Here we make a list of all possible HTTP response status codes that performing a
GET
HTTP request againsthttps://yesno.wtf/api
might return. - Well, maybe not all the ones it might return. But all the ones we care to teach our Flow to anticipate.
- I tried my best to break
https://yesno.wtf/api
– like visitinghttps://yesno.wtf/api?force=HelloWorld
– and couldn’t ever get it to return anything but200
(success) with well-formatted (although sometimes unexpected in terms of its contents) data – so I think it’s safe to only specify what happens in response to200
. - We make up a human-friendly “description like “
successful operation
” (it’s pretty standard to match what the200
code is actually officially named in this part). - We also add a “schema” sub-property and give it a value of “
$ref: '#/definitions/YesNoMaybe'
” to say, “Computer – go seeYesNoMaybe
, below, if you really want to know what the response will look like.”
- Here we make a list of all possible HTTP response status codes that performing a
Phew! Just one thing left: let’s dig into “parameters.”
Good question. I wrote it by hand, using an online tool to facilitate the effort.
I think it might’ve been SmartBear’s “Swagger Hub,” but that’s now behind a login-wall rather than out in the open, so I’m not 100% sure. To get onto its free tier, sign up, ignore the prompt to do a 14-day trial, visit pricing, click “Start Now” in the free tier, and log in again. That should take you to https://app.swaggerhub.com/home. Create a new “API” off their “pet store” template and cut/paste/edit pieces of it around until you think it represents the API you’re working with.
Note that you use SwaggerHub in a text-editing format called YAML. Like CSV and XML and JSON, YAML is a set of punctuation standards that let you give structure to plaintext data. Like CSV files, things like spacing and line breaks can be part of the meaningful, structural punctuation. But like XML and JSON, YAML is meant to represent more complex data structures than CSV is meant to represent. I hope that helps you get started guessing how you might edit it.
When you have something you’re happy with … okay, shoot, where’s the “export to JSON” button …
Ah! You know what? I did all my guessing-and-editing at SmartBear’s login-free editor https://editor.swagger.io/. But I like the one behind the login-wall now that I see it, for development work. The nav panel on the login-wall one helps you jump around the code editor more easily.
You can see the YAML version of my “Swagger / OpenAPI 2.0”-formatted schema for YesNo here, if it helps to have that as well as the “pet store” example. Remember, you can find sample output from the YesNo API endpoint here or here and its documentation here.
When you’re happy with your YAML specification and feel like the preview structure at left and right in the behind-the-login-wall editor represent how your real-world API actually behaves (or at least how the part of it that you want to expose to Flow behaves), copy and paste your YAML into https://editor.swagger.io/ and click “File” - “Convert and save as JSON”.
That’s the text you’ll need to paste into Salesforce’s “Service Schema Complete JSON” box.
Good luck!