Sample 1 Walkthrough
- Running the sample
- JavaScript Walkthrough
- YAML Walkthrough
YAML Walkthrough
Now that you have the sample running, it’s time to look at the Swagger API. Open up PetStore.yaml and let’s go through it.
TIP: All of the behavior discussed on this page is the default behavior of Swagger Express Middleware. You can modify/disable any of this behavior, either by passing options to the middleware, or by adding your own custom logic.
Consumes/Produces
The first section defines the default MIME types that any given operation in the API can consume and produce. Most operations in the Swagger Pet Store API send and receive JSON data, but there are a few that override these default values. For example, the POST /pets/{petName}/photos
operation accepts multipart/form-data
, and the GET /pets/{petName}/photos/{id}
operation produces several different image formats.
TIP: If you try to send a request with a
Content-Type
header that doesn’t match aconsumes
value, then the Validate Request middleware will return an HTTP 415 (Unsupported Media Type) error.
TIP: If you send a request with an
Accept
header that doesn’t match aproduces
value, then the Validate Request middleware will return an HTTP 406 (Not Acceptable) error.
Model Definitions
The next section defines the models for the API: pet
, veterinarian
, and address
. Each model definition is a JSON Schema that defines the model’s properties, whether they’re required or optional, default values, data types, minimum lengths, min/max values, RegEx patterns, enumerations, and more.
TIP: If you send JSON data that doesn’t comply with the model definition, then the Parse Request middleware will return an HTTP 400 (Bad Request) error.
Querying/Deleting Pets
The first two operations in the Pet Store API are GET /pets
and DELETE /pets
. Both of these operations can be called without any query parameters, in which case they will return or delete all pets, respectively. You can also pass one or more query parameters to filter which pets are returned or deleted.
For example, /pets?type=cat would get/delete all pets where type
is “cat”, and /pets?age=4&tags=brown&tags=fluffy would get/delete all pets where age
is 4 and the tags
array contains both “brown” and “fluffy”. You can also filter by nested properties. For example, /pets?vet.address.state=CA would get/delete all pets where the state
of the address
of the vet
is “CA”.
How Filtering Works
This filtering functionality is provided by the Mock middleware. It will only filter by query parameters that are explicitly defined in the Swagger API. For example, the “name” parameter in /pets?name=Fido will be ignored, even though pets do have a name
property, because there is no “name” query parameter defined in the API.
TIP: Notice that all the query parameters are defined in the
definitions
section and theGET
andDELETE
operations use$ref
pointers to reuse the same parameters. This allows us to save about 60 lines of duplicated code.
Response Codes
The GET /pets
and DELETE /pets
operations both define a “default” response code rather than a specific HTTP status code such as 200. Because of this, the Mock middleware will return whichever response code makes the most sense. For GET requests, this is always 200. For DELETE requests, it is 200 (OK) or 204 (No Content), depending on whether or not the operation returns data. In this case, the DELETE operation does return data, so a 200 response code is used.
Response Schema
The GET /pets
and DELETE /pets
operations both define a response schema that is an array of pets. Because of this, the Mock middleware will return the JSON data for all of the pets that match the filter critera. If no pets match the criteria, or there are no pets at all, then an empty array is returned.
If the response schema was just a pet (rather than an array of pets), then the mock middleware would return the first matching pet.
Response Headers
The GET /pets
operation has a Last-Modified
response header defined, so the Mock middleware will automatically set this header correctly. The middleware keeps track of when each object was last modified, so from the list of pets that match the filter criteria, it will set the header to the max modified date/time.
Adding New Pets
The POST /pets
operation lets you add new pets. Each pet that you add gets its own URL. For example, if you add the pet {name: "Fido", type: "dog", age: 4}
, then you can later GET, PATCH, or DELETE this pet at /pets/Fido. But how does this URL get created? Why did it use the pet’s name
property rather than its type
or age
?
Determining the primary key
The Mock middleware tries to determine your model’s primary key using a few different techniques, depending on data types. For object
types, such as our pet
model, it first looks for common property names like id
, key
, username
, name
, etc. If that doesn’t work, then it looks for required properties in your JSON schema. If all else fails, then it just generates a random, unique value.
Response Headers
The POST /pets
operation has a Location
response header defined, so the Mock middleware will automatically set this header to the URL that was created for the pet (using its primary key).
Response Code
The response code for POST /pets
will be 201 (Created), since that’s defined in the API.
Response Schema
The response schema is a pet
object, so the newly-created pet will be returned. If the response schema was an array of pets, then all pets (including the new one) would be returned.
Getting/Editing/Deleting a Pet by Name
The /pets/{petName}
path has three operations: GET
, PATCH
, and DELETE
. These are very similar to the operations we’ve already discussed, except that these three only operate on a single pet, rather than all pets or a filtered list of pets. The Mock middleware will figure out that the {petName}
path parameter corresponds to the name
property on the pet
model (using the same logic as before). This would still work, even if the parameter name was completely different, like theThingICallMyPet
.
Since the pet is determined by the {petName}
parameter, the GET
and DELETE
operations don’t need to pass any other parameters. The PATCH
operation accepts a pet
parameter that is the JSON data to update the pet.
Changing a Pet’s Name
Let’s say you have this pet: {name: "Fido", type: "dog"}
at the URL /pets/Fido, and you decide you want to change Fido’s name to “Fluffy”. So, you send a PATCH
request to /pets/Fido with the data {name: "Fluffy", type: "dog"}
. Presto! Fido is now Fluffy. Except for one thing: Fluffy’s URL is still /pets/Fido, not /pets/Fluffy. Why is that?
Even though the Mock middleware is pretty sure the URL should be /pets/Fluffy, it will do exactly what you told it to do, which is to save the new pet data to the URL you specified. But what if you really want the URL to change whenever a pet’s name changes? That’s a perfect situation for some custom middleware logic, which we cover in the Sample 2 Walkthrough.
PUT vs PATCH
The Mock middleware treats PUT
and PATCH
operations slightly differently. A PATCH
operation merges the new data with the old data, while a PUT
operation overwrites the old data entirely.
Adding Photos
Up to now, we’ve only been looking at operations that send and receive JSON data. But the POST /pets/{petName}/photos
operation breaks that trend. It consumes multipart/form-data
, consisting of two string parameters, an integer parameter, and our first file parameter.
Auto-Generated IDs
The label
and photo
parameters are required. description
and id
are optional. If you don’t specify a value for the description
parameter, then it will be left undefined. If you don’t specify a value for the id
parameter, then the Mock middleware will automatically set it to a random, unique value. This is because the mock middleware uses the same logic as before to determine that the id
is the primary key for a photo. Whenever a primary key is not set, the mock middleware will set it.
Min/Max File Size
Notice that the photo
parameter has a minLength
and maxLength
specified. The Parse Request middleware will return an HTTP 400 (Bad Request) error if the file is too small or too large.
Listing Photos
The POST
and GET
operations both have an object
response schema defined. The properties of this schema correspond to the four parameters of the POST
request. The photo
property is not the raw binary image data, but rather an object containing information about the photo, such as file name, size, MIME type, etc. We’ll discuss how to get the actual image a bit later.
Getting/Deleting a Photo by ID
The GET /pets/{petName}/photos/{id}
and DELETE /pets/{petName}/photos/{id}
operations should seem pretty straightforward by now. Just as before, the {petName}
parameter corresponds to the pet’s name
property, and the {id}
parameter corresponds to the photo’s id
.
Returning the Actual Image
The GET
operation has a new twist. Rather than returning JSON data, it returns the actual image file that you uploaded. This is accomplished by two things: First, the produces
MIME types are all image/*
rather than application/json
, and second, the response schema is type: file
rather than type: object
. Whenever the Mock middleware encouters a file
response schema, it will return the raw file data rather than the JSON object describing the file.
TIP: If the image file no longer exists on the server (such as if it has been deleted), then the mock middleware will return an HTTP 410 (Gone) response.
Empty DELETE Response
Notice that the DELETE
operation does not have a response schema defined. It simply has a default
response code and that’s all. Because of this, the Mock middleware will send an HTTP 204 (No Content) response rather than an HTTP 200 (OK).
Default/Example Responses
The very last thing in the Swagger Pet Store API is GET /
operation. This operation is what serves the HTML page that you see whenever you go to http://localhost:8000. How does this work? The Swagger 2.0 spec allows you to specify default
and example
values for response schemas, model schemas, and parameters, and Swagger Express Middleware will automatically use these values whenever no other value is available. In this case, the response schema for the GET /
operation has a default
value that points to the index.html file, so that file gets served as the response. It doesn’t have to be an HTML file though. Any type of file would work, or you could include a literal default value such as: default: "<h1>Hello World</h1>"
or default: {title: "Hello World", message: "Welcome to the Swagger Pet Store"}
. Of course, you’ll want to make sure your default
value and your produces
MIME types match.
Sample 1 Walkthrough
- Running the sample
- JavaScript Walkthrough
- YAML Walkthrough