-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added REST API guide #362
base: main
Are you sure you want to change the base?
Added REST API guide #362
Conversation
I've been meaning to write something like this myself. The general gist of the content looks pretty good, but it needs some proof reading and editing for grammar/clarity. |
I'm happy to make the changes if you see any problems. Or feel free to add commits as well. |
this one seems quite useful for docs, can this be merged? cc @Krzysztof-Cieslak , probably needs updates but at least is a start? |
|
||
# Creating REST API | ||
|
||
Starting from the [how to start guide](how-to-start.html), we will create a Book API to get, insert, update, and delete Books. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get, insert, update, and delete
create, read, update, and delete
|
||
## Configure Endpoint Routing | ||
|
||
We will be using Endpoint Routing for the application. See [here](https://saturnframework.org/explanations/endpoint-routing.html) for more information. To do this. Add `open Saturn.Endpoint` to the Router.fs and BooksController.fs files. Then inside Program.fs, replace `use_router Router.appRouter` with `use_endpoint_router Router.appRouter`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We will be using [Endpoint Routing](https://saturnframework.org/explanations/endpoint-routing.html) for the application. To do this, add
} | ||
``` | ||
|
||
With the setup done earlier, this will set the base of our Books API endpoints at `"http://localhost:8085/api/books/"`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the setup done earlier, this
This will be the base of our Books API endpoints at "http://localhost:8085/api/books/"
.
|
||
With the setup done earlier, this will set the base of our Books API endpoints at `"http://localhost:8085/api/books/"`. | ||
|
||
We have not create the action functions yet. This router will automatically pass `HttpFunc` and `HttpContext` to our functions. All our action functions will have those as our parameter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have not create the action functions yet. This router will automatically pass HttpFunc
and HttpContext
to our functions. All our action functions will have those as our parameter.
This router will automatically pass HttpFunc
and HttpContext
to our action functions as parameters. Now, let's create our action functions.
|
||
We have not create the action functions yet. This router will automatically pass `HttpFunc` and `HttpContext` to our functions. All our action functions will have those as our parameter. | ||
|
||
For GET, we need no id to get all book so the route will just the current location. Because of `forward "/books" Books.Controller.apiRouter` inside our Router.fs file. The path for our GET request is `"http://localhost:8085/api/books/"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For GET, we need no id to get all book so the route will just the current location. Because of forward "/books" Books.Controller.apiRouter
inside our Router.fs file. The path for our GET request is "http://localhost:8085/api/books/"
We don't need an id to return a list of all books so the path for our GET request is "http://localhost:8085/api/books/"
thanks to forward "/books" Books.Controller.apiRouter
inside our Router.fs file.
|
||
For GET, we need no id to get all book so the route will just the current location. Because of `forward "/books" Books.Controller.apiRouter` inside our Router.fs file. The path for our GET request is `"http://localhost:8085/api/books/"` | ||
|
||
To get a specific book by id, we will need to get our id from the URL. For that, we will use `getf` and the format string `"/%s"` to read the string from the URL and pass it on to our function. You can also write this as `getf "/%s" getByIdAction`. Refer to the table below to modify the format string to your need (e.g. use `"/%i"` if your id is an int). So to get the book with the id of 2, create a GET request to `"http://localhost:8085/api/books/2"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get a specific book by id, we will need to get our id from the URL. For that, we will use getf
and the format string "/%s"
to read the string from the URL and pass it on to our function. You can also write this as getf "/%s" getByIdAction
. Refer to the table below to modify the format string to your need (e.g. use "/%i"
if your id is an int). So to get the book with the id of 2, create a GET request to "http://localhost:8085/api/books/2"
To get a specific book by id, we will need to get our id from the URL. For instance, to get a book with an id of 2, we would make a GET request to "http://localhost:8085/api/books/2"
. For that, we will use getf
and the format string "/%s"
to read the string from the URL and pass it on to our function. You can also write this as getf "/%s" getByIdAction
. Refer to the table below to modify the format string to your need (e.g. use "/%i"
if your id is an int).
|
||
The id is needed for DELETE so we use `deletef`. | ||
|
||
## GET |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe this could be merged with the GET router explainer above? Same with POST, PUT, and DELETE?
| `%f` | `float`/`double` | | ||
| `%O` | `Guid` | | ||
|
||
For POST, we need to parse the object passed in with the request. Generally, this is a json object so `bindJson` is used. To test, send a POST request to `"http://localhost:8085/api/books/"` with the object inside the body as JSON. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally, this is a json JSON object
|
||
## DELETE | ||
|
||
Deletion required the id of the object to be deleted. We need a check to see that the book with the id exist. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
required
requires
|
||
## PUT | ||
|
||
To update a book, we need the id and the book object with the updated data. First, we check that there is a book with the same id. Then we check that the data is valid. Then we update the book. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the book object with updated data
a book object with updated data
|
||
All our REST action methods will require a `HttpFunc` and `HttpContext` object passed in. We use the `HttpContext` object to retrieve our connection string and in returning the response code. The `HttpFunc` object is not used but is required for our router function. | ||
|
||
We also need a GET action for retrieving just one item by id. Create a new function with the id in the parameter. We will return a `404 Not Found` error if no book exists with that id. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need a GET action for retrieving just one to retrieve an item by id.
} | ||
``` | ||
|
||
This GET request will return an `200 OK` with the list of books inside our database. If there is a problem getting data from the database, return a `500 Internal Error`. You can also use `return! (Successful.OK (List.ofSeq result) next ctx)` and `return! (ServerErrors.INTERNAL_ERROR ex.Message next ctx)` for OK and Internal Error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This GET request will return an a 200 OK
|
||
## DELETE | ||
|
||
For the delete. Send a DELETE request with the id in the URL address. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the delete. Send a DELETE request with the id in the URL address.
Added guide for creating and consuming REST API since it was something I was looking for in my project. Feedback is welcome whether on the text or code in the guide.