Skip to content
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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

vtquan
Copy link

@vtquan vtquan commented Nov 2, 2022

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.

@drewknab
Copy link

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.

@vtquan
Copy link
Author

vtquan commented Dec 5, 2022

I'm happy to make the changes if you see any problems. Or feel free to add commits as well.

@jkone27
Copy link

jkone27 commented Jul 31, 2024

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.
Copy link

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`.
Copy link

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/"`.
Copy link

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.
Copy link

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/"`
Copy link

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"`
Copy link

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
Copy link

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.
Copy link

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.
Copy link

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.
Copy link

@drewknab drewknab Aug 6, 2024

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.
Copy link

@drewknab drewknab Aug 6, 2024

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.
Copy link

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.
Copy link

@drewknab drewknab Aug 6, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants