doc: update blog tutorial to updated syntax and instructions (#10577)
parent
de6784a007
commit
be7c3965a9
|
@ -49,13 +49,12 @@ V projects can be created anywhere and don't need to have a certain structure:
|
|||
|
||||
```bash
|
||||
mkdir blog
|
||||
cd blog
|
||||
touch blog.v
|
||||
v init
|
||||
```
|
||||
|
||||
First, let's create a simple hello world website:
|
||||
|
||||
```v
|
||||
```v oksyntax
|
||||
// blog.v
|
||||
module main
|
||||
|
||||
|
@ -66,9 +65,11 @@ struct App {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
vweb.run(&App{}, 8081)
|
||||
app := App{}
|
||||
vweb.run(app, 8081)
|
||||
}
|
||||
|
||||
['/index']
|
||||
pub fn (mut app App) index() vweb.Result {
|
||||
return app.text('Hello world from vweb!')
|
||||
}
|
||||
|
@ -185,30 +186,6 @@ Now let's display some articles!
|
|||
We'll be using V's builtin ORM and a SQLite database.
|
||||
(V ORM will also support MySQL, Postgre, and SQL Server soon.)
|
||||
|
||||
Create a SQLite file with the schema:
|
||||
```sql
|
||||
-- blog.sqlite
|
||||
drop table if exists Article;
|
||||
|
||||
create table Article (
|
||||
id integer primary key,
|
||||
title text default "",
|
||||
text text default ""
|
||||
);
|
||||
|
||||
insert into Article (title, text) values (
|
||||
"Hello, world!",
|
||||
"V is great."
|
||||
);
|
||||
|
||||
insert into Article (title, text) values (
|
||||
"Second post.",
|
||||
"Hm... what should I write about?"
|
||||
);
|
||||
```
|
||||
|
||||
Run the file with `sqlite3 blog.db < blog.sqlite`.
|
||||
|
||||
|
||||
Add a SQLite handle to `App`:
|
||||
|
||||
|
@ -219,7 +196,7 @@ import vweb
|
|||
|
||||
struct App {
|
||||
vweb.Context
|
||||
mut:
|
||||
pub mut:
|
||||
db sqlite.DB
|
||||
}
|
||||
```
|
||||
|
@ -231,16 +208,42 @@ Add the `init_server()` method where we'll connect to a database:
|
|||
```v oksyntax
|
||||
// blog.v
|
||||
pub fn (mut app App) init_server() {
|
||||
db := sqlite.connect(':memory:') or { panic(err) }
|
||||
db.exec('create table `Article` (id integer primary key, title text default "", text text default "")')
|
||||
db.exec('insert into Article (title, text) values ("Hello, world!", "V is great.")')
|
||||
db.exec('insert into Article (title, text) values ("Second post.", "Hm... what should I write about?")')
|
||||
app.db = db
|
||||
app.db = sqlite.connect(':memory:') or { panic(err) }
|
||||
sql app.db {
|
||||
create table Article
|
||||
}
|
||||
|
||||
first_article := Article{
|
||||
title: 'Hello, world!'
|
||||
text: 'V is great.'
|
||||
}
|
||||
|
||||
second_article := Article{
|
||||
title: 'Second post.'
|
||||
text: 'Hm... what should I write about?'
|
||||
}
|
||||
|
||||
sql app.db {
|
||||
insert first_article into Article
|
||||
insert second_article into Article
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Code in the `init_server()` function is run only once during app's startup, so we are going
|
||||
to have one DB connection for all requests.
|
||||
to have one DB connection for all requests. Modify the main method to call the `init_server()`
|
||||
function before adding it to the vweb system:
|
||||
|
||||
```v oksyntax
|
||||
fn main() {
|
||||
mut app := App{}
|
||||
app.init_server()
|
||||
vweb.run(app, 8081)
|
||||
}
|
||||
```
|
||||
|
||||
Because `init_server()` modifies properties of the app struct we now have to make it mutable
|
||||
with the `mut` keyword.
|
||||
|
||||
Create a new file `article.v`:
|
||||
|
||||
|
@ -250,7 +253,7 @@ Create a new file `article.v`:
|
|||
module main
|
||||
|
||||
struct Article {
|
||||
id int
|
||||
id int [primary; sql: serial]
|
||||
title string
|
||||
text string
|
||||
}
|
||||
|
@ -262,11 +265,15 @@ pub fn (app &App) find_all_articles() []Article {
|
|||
}
|
||||
```
|
||||
|
||||
Notice that the `Article` structure conforms to the same structure and naming as
|
||||
the database table in the creation SQL statement. Also we need to add ORM decorators
|
||||
to our primary key to let it know that it is the primary key and it should auto-increment
|
||||
|
||||
Let's fetch the articles in the `index()` action:
|
||||
|
||||
```v ignore
|
||||
// blog.v
|
||||
pub fn (app &App) index() vweb.Result {
|
||||
pub fn (app App) index() vweb.Result {
|
||||
articles := app.find_all_articles()
|
||||
return $vweb.html()
|
||||
}
|
||||
|
@ -319,7 +326,7 @@ pub fn (app &App) retrieve_article() ?Article {
|
|||
V ORM uses V's optionals for single values, which is very useful, since
|
||||
bad queries will always be handled by the developer:
|
||||
|
||||
```v oksyntax
|
||||
```v ignore
|
||||
// article.v
|
||||
article := app.retrieve_article(10) or {
|
||||
app.text('Article not found')
|
||||
|
@ -347,10 +354,10 @@ Create `new.html`:
|
|||
</html>
|
||||
```
|
||||
|
||||
```v oksyntax
|
||||
```v ignore
|
||||
// article.v
|
||||
import vweb
|
||||
|
||||
['/new_article'; post]
|
||||
pub fn (mut app App) new_article() vweb.Result {
|
||||
title := app.form['title']
|
||||
text := app.form['text']
|
||||
|
@ -372,12 +379,25 @@ pub fn (mut app App) new_article() vweb.Result {
|
|||
> Untyped `form['key']` is temporary. Very soon Vweb will accept query and form
|
||||
parameters via function arguments: `new_article(title, text string) {`.
|
||||
|
||||
The decorator on our function tells vweb the path to our endpoint, `/new_article`,
|
||||
and that it is an HTTP POST type operation.
|
||||
|
||||
We need to update `index.html` to add a link to the "new article" page:
|
||||
|
||||
```html
|
||||
<a href='/new'>New article</a>
|
||||
```
|
||||
|
||||
Next we need to add the HTML endpoint to our code like we did with `index.html`:
|
||||
|
||||
```v ignore
|
||||
['/new']
|
||||
pub fn (mut app App) new() vweb.Result {
|
||||
return $vweb.html()
|
||||
}
|
||||
```
|
||||
|
||||
Re-running this code will now allow us to add new posts to our blog endpoint
|
||||
|
||||
|
||||
### JSON endpoints
|
||||
|
@ -391,14 +411,34 @@ in V is very simple:
|
|||
import vweb
|
||||
import json
|
||||
|
||||
['/articles'; get]
|
||||
pub fn (mut app App) articles() vweb.Result {
|
||||
articles := app.find_all_articles()
|
||||
return app.json(json.encode(articles))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<img width=662 src="https://github.com/vlang/v/blob/master/tutorials/building_a_simple_web_blog_with_vweb/img/articles_json.png?raw=true">
|
||||
|
||||
### Persistent data
|
||||
If one wants to persist data they need to use a file instead of memory SQLite Database.
|
||||
Replace the `init_server()` function with this instead:
|
||||
|
||||
```v oksyntax
|
||||
// blog.v
|
||||
pub fn (mut app App) init_server() {
|
||||
app.db = sqlite.connect('blog.db') or { panic(err) }
|
||||
sql app.db {
|
||||
create table Article
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As we can see it attempts to open a file in the current directory named `blog.db`.
|
||||
If the database file doesn't exist it will create it. The second command will
|
||||
create the table `Article` if none exists already. Now every time the
|
||||
app is run you will see the articles created from the previous executions
|
||||
|
||||
|
||||
To be continued...
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module main
|
||||
|
||||
struct Article {
|
||||
id int
|
||||
id int [primary; sql: serial]
|
||||
title string
|
||||
text string
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ pub mut:
|
|||
}
|
||||
|
||||
fn main() {
|
||||
vweb.run(&App{}, 8081)
|
||||
mut app := App{}
|
||||
app.init_server()
|
||||
vweb.run(app, 8081)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -27,6 +29,7 @@ pub fn (app &App) index_html() vweb.Result {
|
|||
return $vweb.html()
|
||||
}
|
||||
*/
|
||||
['/index']
|
||||
pub fn (app &App) index() vweb.Result {
|
||||
articles := app.find_all_articles()
|
||||
return $vweb.html()
|
||||
|
@ -34,17 +37,16 @@ pub fn (app &App) index() vweb.Result {
|
|||
|
||||
pub fn (mut app App) init_server() {
|
||||
app.db = sqlite.connect('blog.db') or { panic(err) }
|
||||
app.db.create_table('article', [
|
||||
'id integer primary key',
|
||||
"title text default ''",
|
||||
"text text default ''",
|
||||
])
|
||||
sql app.db {
|
||||
create table Article
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut app App) before_request() {
|
||||
app.user_id = app.get_cookie('id') or { '0' }
|
||||
}
|
||||
|
||||
['/new']
|
||||
pub fn (mut app App) new() vweb.Result {
|
||||
return $vweb.html()
|
||||
}
|
||||
|
@ -69,10 +71,10 @@ pub fn (mut app App) new_article() vweb.Result {
|
|||
return app.redirect('/')
|
||||
}
|
||||
|
||||
pub fn (mut app App) articles() {
|
||||
['/articles'; get]
|
||||
pub fn (mut app App) articles() vweb.Result {
|
||||
articles := app.find_all_articles()
|
||||
x := json.encode(articles)
|
||||
app.json(x)
|
||||
return app.json(json.encode(articles))
|
||||
}
|
||||
|
||||
fn (mut app App) time() {
|
||||
|
|
Loading…
Reference in New Issue