Skip to content

Commit 2f272ad

Browse files
authored
Update with beta.1 changes (#3)
- toucan 1.0.0-beta.1 updates
1 parent 556134b commit 2f272ad

File tree

87 files changed

+253
-227
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+253
-227
lines changed

docs/10-little-uikit-tips-you-should-know/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ <h2 class="title"><a href="https://theswiftdev.com/building-input-forms-for-ios-
484484
</div>
485485
<div class="meta">
486486
<time datetime="2018/10/16">2018/10/16</time>
487-
&middot; <span class="reading-time">4 min read</span>
487+
&middot; <span class="reading-time">5 min read</span>
488488
</div>
489489

490490
<h2 class="title"><a href="https://theswiftdev.com/custom-uiview-subclass-from-a-xib-file/" target="">Custom UIView subclass from a xib file</a></h2>

docs/a-generic-crud-solution-for-vapor-4/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ <h1>A generic CRUD solution for Vapor 4</h1>
108108
<p>Learn how to build a controller component that can serve models as JSON objects through a RESTful API written in Swift.</p>
109109
<section>
110110

111-
<h2 id="crud-create-read-update-and-delete">CRUD ~ Create, Read, Update and Delete</h2><p>We should start by implementing the non-generic version of our code, so after we see the pattern we can turn it into a more generalized Swift code. If you start with the <a href="https://github.com/vapor/api-template" target="_blank">API template</a> project there is a pretty good example for almost everything using a Todo model.</p><blockquote><p>NOTE: Start a new project using the <a href="http://docs.vapor.codes/3.0/getting-started/toolbox/" target="_blank">toolbox</a>, just run <code>vapor new myProject</code></p></blockquote><p>Open the project by double clicking the <code>Package.swift</code> file, that’ll fire up Xcode (you should be on version 11.4 or later). If you open the <code>Sources/App/Controllers</code> folder you’ll find a sample controller file there called <code>TodoController.swift</code>. We’re going to work on this, but first…</p><blockquote><p>A controller is a collection of request handler functions around a specific model.</p></blockquote><h2 id="http-basics-request---response">HTTP basics: Request -> Response</h2><p><a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol" target="_blank">HTTP</a> is a text transfer protocol that is widely used around the web. In the beginning it was only used to transfer HTML files, but nowadays you can use it to request almost anything. It’s mostly a stateless protocol, this means you request something, you get back a response and that’s it.</p><p>It’s like ordering a pizza from a place through phone. You need a number to call (URL), you pick up the phone, dial the place, the phone company initializes the connection between (you & the pizza place) the two participants (the network layer does the same thing when you request an URL from a server). The phone on the other side starts ringing. 📱</p><p>Someone picks up the phone. You both introduce yourselves, also exchange some basic info such as the delivery address (server checks HTTP headers & discovers what needs to be delivered to where). You tell the place what kind of pizza you’d like to have & you wait for it. The place cooks the pizza (the server gathers the necessary data for the response) & the pizza boy arrives with your order (the server sends back the actual response). 🍕</p><blockquote><p>Everything happens asynchronously, the place (server) can fulfill multiple requests. If there is only one person who is taking orders & cooking pizzas, sometimes the cooking process will be blocked by answering the phone. Anyways, using non-blocking i/o is important, that’s why Vapor uses Futures & Promises from <a href="https://github.com/apple/swift-nio" target="_blank">SwiftNIO</a> under the hood.</p></blockquote><p>In our case the request is a URL with some extra headers (key, value pairs) and a request body object (encoded data). The response is usually made of a HTTP status code, optional headers and response body. If we are talking about a RESTful API, the encoding of the body is usually JSON.</p><p>All right then, now you know the basics it’s time to look at some Swift code.</p><h2 id="contents-and-models-in-vapor">Contents and models in Vapor</h2><p>Defining a data structure in Swift is pretty easy, you just have to create a struct or a class. You can also convert them back and forth to JSON using the built-in <a href="https://theswiftdev.com/how-to-parse-json-in-swift-using-codable-protocol/">Codable protocol</a>. Vapor has an extension around this called Content. If you conform the the protocol (no need to implement any new functions, the object just needs to be Codable) the system can decode these objects from requests and encode them as responses.</p><p>Models on the other hand represent rows from your database. The <a href="https://theswiftdev.com/a-tutorial-for-beginners-about-the-fluent-postgresql-driver-in-vapor-4/">Fluent</a> ORM layer can take care of the low level abstractions, so you don’t have to mess around with SQL queries. This is a great thing to have, read my other article if you like to know more about Fluent. 💾</p><p>The problem starts when you have a model and it has different fields than the content. Imagine if this Todo model was a User model with a secret password field? Would you like to expose that to the public when you encode it as a response? Nope, I don’t think so. 🙉</p><p>I believe that in most of the Cases the Model and the Content should be separated. Taking this one step further, the content of the request (input) and the content of the response (output) is sometimes different. I’ll stop it now, let’s change our Todo model according to this.</p><pre><code class="language-swift">import Fluent
111+
<h2 id="crud-create-read-update-and-delete">CRUD ~ Create, Read, Update and Delete</h2><p>We should start by implementing the non-generic version of our code, so after we see the pattern we can turn it into a more generalized Swift code. If you start with the <a href="https://github.com/vapor/api-template" target="_blank">API template</a> project there is a pretty good example for almost everything using a Todo model.</p><blockquote class="note"><p>NOTE: Start a new project using the <a href="http://docs.vapor.codes/3.0/getting-started/toolbox/" target="_blank">toolbox</a>, just run <code>vapor new myProject</code></p></blockquote><p>Open the project by double clicking the <code>Package.swift</code> file, that’ll fire up Xcode (you should be on version 11.4 or later). If you open the <code>Sources/App/Controllers</code> folder you’ll find a sample controller file there called <code>TodoController.swift</code>. We’re going to work on this, but first…</p><blockquote><p>A controller is a collection of request handler functions around a specific model.</p></blockquote><h2 id="http-basics-request---response">HTTP basics: Request -> Response</h2><p><a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol" target="_blank">HTTP</a> is a text transfer protocol that is widely used around the web. In the beginning it was only used to transfer HTML files, but nowadays you can use it to request almost anything. It’s mostly a stateless protocol, this means you request something, you get back a response and that’s it.</p><p>It’s like ordering a pizza from a place through phone. You need a number to call (URL), you pick up the phone, dial the place, the phone company initializes the connection between (you & the pizza place) the two participants (the network layer does the same thing when you request an URL from a server). The phone on the other side starts ringing. 📱</p><p>Someone picks up the phone. You both introduce yourselves, also exchange some basic info such as the delivery address (server checks HTTP headers & discovers what needs to be delivered to where). You tell the place what kind of pizza you’d like to have & you wait for it. The place cooks the pizza (the server gathers the necessary data for the response) & the pizza boy arrives with your order (the server sends back the actual response). 🍕</p><blockquote><p>Everything happens asynchronously, the place (server) can fulfill multiple requests. If there is only one person who is taking orders & cooking pizzas, sometimes the cooking process will be blocked by answering the phone. Anyways, using non-blocking i/o is important, that’s why Vapor uses Futures & Promises from <a href="https://github.com/apple/swift-nio" target="_blank">SwiftNIO</a> under the hood.</p></blockquote><p>In our case the request is a URL with some extra headers (key, value pairs) and a request body object (encoded data). The response is usually made of a HTTP status code, optional headers and response body. If we are talking about a RESTful API, the encoding of the body is usually JSON.</p><p>All right then, now you know the basics it’s time to look at some Swift code.</p><h2 id="contents-and-models-in-vapor">Contents and models in Vapor</h2><p>Defining a data structure in Swift is pretty easy, you just have to create a struct or a class. You can also convert them back and forth to JSON using the built-in <a href="https://theswiftdev.com/how-to-parse-json-in-swift-using-codable-protocol/">Codable protocol</a>. Vapor has an extension around this called Content. If you conform the the protocol (no need to implement any new functions, the object just needs to be Codable) the system can decode these objects from requests and encode them as responses.</p><p>Models on the other hand represent rows from your database. The <a href="https://theswiftdev.com/a-tutorial-for-beginners-about-the-fluent-postgresql-driver-in-vapor-4/">Fluent</a> ORM layer can take care of the low level abstractions, so you don’t have to mess around with SQL queries. This is a great thing to have, read my other article if you like to know more about Fluent. 💾</p><p>The problem starts when you have a model and it has different fields than the content. Imagine if this Todo model was a User model with a secret password field? Would you like to expose that to the public when you encode it as a response? Nope, I don’t think so. 🙉</p><p>I believe that in most of the Cases the Model and the Content should be separated. Taking this one step further, the content of the request (input) and the content of the response (output) is sometimes different. I’ll stop it now, let’s change our Todo model according to this.</p><pre><code class="language-swift">import Fluent
112112
import Vapor
113113

114114
final class Todo: Model {
@@ -134,7 +134,7 @@ <h2 id="crud-create-read-update-and-delete">CRUD ~ Create, Read, Update and Dele
134134
self.title = title
135135
}
136136
}
137-
</code></pre><p>We expect to have a title when we insert a record (we can generate the id), but when we’re returning Todos we can expose the id property as well. Now back to the controller.</p><blockquote><p>WARN: Don’t forget to run Fluent migrations first: <code>swift run Run migrate</code></p></blockquote><h3 id="create">Create</h3><p>The flow is pretty simple. Decode the Input type from the content of the request (it’s created from the HTTP body) and use it to construct a new Todo class. Next save the newly created item to the database using Fluent. Finally after the save operation is done (it returns nothing by default), map the future into a proper Output, so Vapor can encode this to JSON format.</p><pre><code class="language-swift">import Fluent
137+
</code></pre><p>We expect to have a title when we insert a record (we can generate the id), but when we’re returning Todos we can expose the id property as well. Now back to the controller.</p><blockquote class="warning"><p>WARN: Don’t forget to run Fluent migrations first: <code>swift run Run migrate</code></p></blockquote><h3 id="create">Create</h3><p>The flow is pretty simple. Decode the Input type from the content of the request (it’s created from the HTTP body) and use it to construct a new Todo class. Next save the newly created item to the database using Fluent. Finally after the save operation is done (it returns nothing by default), map the future into a proper Output, so Vapor can encode this to JSON format.</p><pre><code class="language-swift">import Fluent
138138
import Vapor
139139

140140
struct TodoController {
@@ -378,7 +378,7 @@ <h2 id="crud-create-read-update-and-delete">CRUD ~ Create, Read, Update and Dele
378378
.init(id: self.id!.uuidString, title: self.title)
379379
}
380380
}
381-
</code></pre><blockquote><p>NOTE: If the input is the same as the output, you just need one (<code>Context</code>?) struct instead of two.</p></blockquote><p>This is what’s left off the controller (not much, haha):</p><pre><code class="language-swift">struct TodoController: ApiController {
381+
</code></pre><blockquote class="note"><p>NOTE: If the input is the same as the output, you just need one (<code>Context</code>?) struct instead of two.</p></blockquote><p>This is what’s left off the controller (not much, haha):</p><pre><code class="language-swift">struct TodoController: ApiController {
382382
typealias Model = Todo
383383
}
384384
</code></pre><p>The router object also shortened a bit:</p><pre><code class="language-swift">func routes(_ app: Application) throws {

0 commit comments

Comments
 (0)