This web API acts as a collection of National and State Parks. Users are able to see a list of all parks, as well as add parks, edit, or delete parks.
- C#
- .NET 7.0
- Postman
- Swagger
- MySQL Workbench
- NewtonSoft
- Identity
- Jwt Tokens
- Markdown
- Git
This API implements token-based authorization for any destructive actions. Any user can GET
the full list of parks saved in the database, as well as GET
just one specific park by {id}. GET
requests for a non-specific park also returns the Total Park Count and is paginated. In order to be able to POST
, PUT
, PATCH
, or DELETE
a park from the API, users must be authorized.
- Clone this repository.
- Open the terminal and navigate to this project's production directory. called "ParksApi". Run the command
dotnet restore
to restore all necessary packages. - Then, still within the production directory "ParksApi", create a new file called
appsettings.json
. - Within
appsettings.json
, put in the following code, replacing the[YOUR-USERNAME-HERE]
and[YOUR-PASSWORD-HERE]
with your own credentials for MySQL. You will also need to replace[RANDOM-STRING]
with your own string. I recommend a random string generator such as this one
{
"AllowedHosts": "*",
"Jwt": {
"Key": "[RANDOM-STRING]",
"Issuer": "https://localhost:44390",
"Audience": "https://localhost:44390"
},
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Port=3306;database=parks_api;uid=[YOUR-USERNAME-HERE];pwd=[YOUR-PASSWORD-HERE];"
}
}
- Ensure you save the changes made to the
appsettings.json
file and then run the commanddotnet ef database update
in the command line. This will create the base database in MySQL Workbench including the parks that are hard-coded into the database. - Within the production directory "ParksApi", run
dotnet watch run
in the command line to start the project in development mode.
REMINDER: this is an insecure but simplified way to handle user credentials. For added security, consider implementing a database to hold your User information
- Navigate to the file
ParksApi.Solution/ParksApi/Models/UserConstants.cs
. - Either un-comment out or copy-paste the commented out portion and fill in with new user's information. Note: there must be a comma separating each new User()
new User() { Username = "newUser", Password = "NewPassword1!", Email = "email@email.com", Name = "new user" },
- Repeat Step 2 for each new user you would like to authorize
POST
,PUT
,PATCH
, andDELETE
functionality for. - Ensure your changes are saved and run the command
dotnet watch run
in the command line to start the project in development mode.
- With the project running in development mode, access your tool of choice to contact the API (i.e. Swagger, Postman, etc.)
- Make a
POST
request that includes your login credentials (added to theUserConstants.cs
file in theModels
sub-directory) in the body. Here's an example in JSON:
POST http://localhost:5002/api/Login
{
"username": "[YOUR-USERNAME]",
"password": "[YOUR-PASSWORD]"
}
- If your login is successful, the response body will generate a long string of randomized characters. This will be your token and it expires in 15 minutes. Either copy your token, or start additional requests in a different window so that you're able to reference your token as needed, until it expires.
Parameter | Type | Required | Description |
---|---|---|---|
city | string | not required | returns parks with a matching city value |
state | string | not required | returns parks with a matching state value |
statePark | boolean | not required | returns parks that have a StatePark property value of true |
nationalPark | boolean | not required | returns parks that have a NationalPark property value of true |
pageSize | integer | default value set to 10 | value is editable to change the amount of parks displayed per page in the response |
page | integer | default value set to 1 | value is editable to change the current page number of results displayed in the response |
The following query will return all parks with a city value of "Aurora":
GET http://localhost:5002/api/parks?city=aurora
The following query will return all parks with a state value of "California":
GET http://localhost:5002/api/parks?state=california
The following query will return all parks with a statePark value of "true":
GET http://localhost:5002/api/parks?statePark=true
It's possible to include multiple query strings by separating them with an &
:
GET http://localhost:5002/api/parks?state=Colorado&nationalPark=true
The following query will return all parks on page 2, and each page will list 3 parks (rather than the default of 10 parks per page, and starting at page 1):
GET http://localhost:5002/api/Parks?page=2&pageSize=3
GET http://localhost:5002/api/Parks?page=1&pageSize=2
{
"queriedParks": [
{
"parkId": 1,
"name": "Grand Canyon National Park",
"city": "Grand Canyon Village",
"state": "Arizona",
"nationalPark": true,
"statePark": false
},
{
"parkId": 2,
"name": "Cherry Creek State Park",
"city": "Aurora",
"state": "Colorado",
"nationalPark": false,
"statePark": true
}
],
"matchingParks": 5,
"totalParks": 8,
"currentPage": 1,
"parksPerPage": 2
}
NOTE: You may choose to update either the page
in the GET
request to see a different page of results, or update pageSize
to a number greater than the number of totalParks
so all parks will display in one page.
Your token must be included with every destructive request or you will receive an Unauthorized
error. Don't forget to include the necessary contents in the body of the request along with your token. I recommend Postman as a tool for these requests as it's easy to attach both
-
Open the Postman application.
-
Under the URL bar for your request, click on Authorization and change the Type to Bearer Token.
-
To the right of the Type drop-down menu is a textbox labeled Token. This is where you will paste that token you received .
-
Along where the Authorization tab was, there is also a Body tab. Navigate to that and ensure the type is set to raw and JSON. In the body area is where you will paste the additional text necessary depending on the type of request you're making. Additional body requirements are as detailed below.
When making a POST
request to http://localhost:5002/api/Parks/
, you need to include a body. Here's an example body in JSON:
{
"name": "Rocky Mountain Nat'l Park",
"city": "Estes Park",
"state": "Colorado",
"nationalPark": true,
"statePark": false
}
When making a PUT
request to http://localhost:5002/api/Parks/{id}
, you need to include a body that includes the park's parkId
property which must match the id number in the URL. Here's an example in JSON:
PUT http://localhost:5002/api/Parks/1
{
"parkId": 1,
"name": "Rocky Mountain National Park",
"city": "Estes Park",
"state": "Colorado",
"nationalPark": true,
"statePark": false
}
When making a PATCH
request to http://localhost:5002/api/Parks/{id}
, you need to include a body that includes the park's property to update, an operation to perform, and a new value. The {id}
in the URL should be replaced with the parkId
of the park you're updating. Here's an example body in JSON:
(Though you may choose to include the old value of the property with "from", it is not required and is only included here for clarity's sake.)
[
{
"path": "city",
"op": "replace",
"from": "Yosemite Nat'l Park",
"value": "Yosemite National Park"
}
]
You are able to update multiple properties at once by chaining together with a comma separating each PATCH
operation. Here's an example body in JSON:
[
{
"path": "city",
"op": "replace",
"from": "Yosemite Nat'l Park",
"value": "Yosemite National Park"
},
{
"path": "statePark",
"op": "remove",
}
]
"op" | result |
---|---|
"replace" | replaces specified path's corresponding property with value specified |
"remove" | resets specified path's corresponding property to null (or false, if boolean) |
NOTE: Though there are additional operations within Patch functionality, this API has not been configured to need or support any other operations aside from REPLACE
and REMOVE
- WIP: add Users to database & remove need for UsersController
- Add a
RANDOM
endpoint that randomly returns a park. - Add a second custom endpoint that accepts parameters. Example: a
SEARCH
route that allows users to search by specific park names. - Add a front end MVC application that consumes this API.
MIT License
Copyright (c) 2023 Luckie