<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ceres/view/recipe.go, branch step-re-ordering</title>
<subtitle>Recipe server for your favorite dishes</subtitle>
<id>https://cgit.xengineering.eu/ceres/atom/view/recipe.go?h=step-re-ordering</id>
<link rel='self' href='https://cgit.xengineering.eu/ceres/atom/view/recipe.go?h=step-re-ordering'/>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/'/>
<updated>2024-10-24T18:14:14Z</updated>
<entry>
<title>view: Order ingredient summary by ingredient name</title>
<updated>2024-10-24T18:14:14Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-10-24T15:24:00Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=9422e8194245c9cdbfa09b38c20173964349e2a2'/>
<id>urn:sha1:9422e8194245c9cdbfa09b38c20173964349e2a2</id>
<content type='text'>
This makes it easier to write a shopping list for the required
ingredients.
</content>
</entry>
<entry>
<title>Switch to http.Handler</title>
<updated>2024-10-23T18:34:57Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-10-23T18:34:57Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=e66691083a2455c29b50a2970c0aba1d6afca753'/>
<id>urn:sha1:e66691083a2455c29b50a2970c0aba1d6afca753</id>
<content type='text'>
The used `func(http.ResponseWriter, *http.Request)` return values made
the HTTP handler factory functions quite unreadable. Thus it is switched
to the http.Handler type.
</content>
</entry>
<entry>
<title>Remove github.com/gorilla/mux dependency</title>
<updated>2024-10-22T19:53:30Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-10-22T19:17:47Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=dbc874e2b9f300bea7a18deda32e784afb0ab89a'/>
<id>urn:sha1:dbc874e2b9f300bea7a18deda32e784afb0ab89a</id>
<content type='text'>
The reason for the introduction of this dependency was that it was easy
to setup routes with HTTP method restrictions.

Since Go 1.22 this feature is part of the standard library. Method
restrictions are part of the patterns used to register routes [1].

[1]: https://pkg.go.dev/net/http#hdr-Patterns-ServeMux
</content>
</entry>
<entry>
<title>model: Replace global db variable by custom type</title>
<updated>2024-10-13T17:55:38Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-10-13T17:52:28Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=473052ed8f2c83052ed5b47a7f4cec68ac2621a6'/>
<id>urn:sha1:473052ed8f2c83052ed5b47a7f4cec68ac2621a6</id>
<content type='text'>
Reducing global variables makes it easier to understand functions
independently of the rest of the code.

Adding the new model.DB type as a custom variant of the sql.DB type
makes it possible to write methods for the database which makes the code
way more readable.
</content>
</entry>
<entry>
<title>Apply go fmt to all source files</title>
<updated>2024-09-11T18:25:54Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-09-11T18:25:31Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=54029aac92f17ec87d3ef0bb73fcdac271b209c9'/>
<id>urn:sha1:54029aac92f17ec87d3ef0bb73fcdac271b209c9</id>
<content type='text'>
This applies default Go code style recommendations.
</content>
</entry>
<entry>
<title>Remove default recipe name</title>
<updated>2024-05-09T10:19:30Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-04-23T15:42:57Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=2704cb76554b02f546bf3f9d2d11be98f2854b7b'/>
<id>urn:sha1:2704cb76554b02f546bf3f9d2d11be98f2854b7b</id>
<content type='text'>
To avoid not clickable recipes on the /recipes page a default name used
to be inserted on recipe creation.

This was not a proper fix for the problem and also was annoying that the
user first had to remove the default recipe name.

This commit removes this default name.
</content>
</entry>
<entry>
<title>Introduce model.Transaction()</title>
<updated>2024-05-08T20:26:00Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-05-08T19:53:13Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=0ba1a7661a81200db98e40149eef1e39fd22f407'/>
<id>urn:sha1:0ba1a7661a81200db98e40149eef1e39fd22f407</id>
<content type='text'>
It is a very common pattern that some function needs to access the
database and wants to wrap all the actions into one transaction.

The advantage of a transaction is that it is ACID:

- atomic
- consistent
- isolated
- durable

In Go it is required to request a new transaction, execute functionality
on it and handle rollback or commit of this transaction based on the
success of the operation.

All this and the error handling can be written down in the
model.Transaction() function exactly once. The full signature of it is:

	func Transaction(f func(*sql.Tx) error) error

It requires a function or closure passed as argument which takes the
transaction (*sql.Tx) and returns an error which might be nil.

This is very generic. It is applied to:

- injecting test data
- database migrations
- data read requests
- data write requests
</content>
</entry>
<entry>
<title>model: Add helper function for safe CRUD</title>
<updated>2024-04-07T08:47:36Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-04-07T08:42:03Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=c4a4a8b5f60a568abd2af614ca4a5d06855bc3a1'/>
<id>urn:sha1:c4a4a8b5f60a568abd2af614ca4a5d06855bc3a1</id>
<content type='text'>
This removes the redundant setup of a database/sql.Tx in each HTTP
handler.
</content>
</entry>
<entry>
<title>model: Always pass *sql.Tx to CRUD methods</title>
<updated>2024-04-06T11:12:17Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-04-06T11:12:17Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=f65b11a5b3011f370df5b4d32239225f3708ecd5'/>
<id>urn:sha1:f65b11a5b3011f370df5b4d32239225f3708ecd5</id>
<content type='text'>
When nesting objects like steps into other objects like recipes it is
required to pass a *sql.Tx value to the CRUD methods of the inner
object to be able to roll back the whole transaction.

The top level object used to be responsible for the creation of this
*sql.Tx inside its CRUD methods.

This is now moved to the caller of the CRUD methods (here the HTTP
handler function). The advantage is that all CRUD methods now accept a
*sql.Tx as only argument which makes those methods more consistent.
</content>
</entry>
<entry>
<title>view: Provide recipe deletion</title>
<updated>2024-03-03T15:44:54Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-03-03T14:11:53Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=bee8b4cc59fd24fc1b924a6160b8eaa221405aeb'/>
<id>urn:sha1:bee8b4cc59fd24fc1b924a6160b8eaa221405aeb</id>
<content type='text'>
</content>
</entry>
<entry>
<title>view: Add 'Read' suffix to function names</title>
<updated>2024-03-03T14:26:07Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-03-03T14:13:55Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=b19326df6f372f9dd8f218d0c5b4d2d8b4d4fc35'/>
<id>urn:sha1:b19326df6f372f9dd8f218d0c5b4d2d8b4d4fc35</id>
<content type='text'>
This reflects that these HTTP handler functions implement one of the
four CRUD methods create, read update and delete.
</content>
</entry>
<entry>
<title>view: Replace edit by view parameter</title>
<updated>2024-03-03T14:05:15Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-03-03T14:05:15Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=25fe18973f11d3db61a1ae9ca05f2bd63d3edea9'/>
<id>urn:sha1:25fe18973f11d3db61a1ae9ca05f2bd63d3edea9</id>
<content type='text'>
The old edit URL parameter allowed to select one different HTML
template. A more generic approach is to provide a view parameter which
allows to use multiple alternative HTML templates for the same data
defined by the Go struct.

This makes implementing additional pages like a confirm page for recipe
deletion easier.
</content>
</entry>
<entry>
<title>model: Use only string types for models</title>
<updated>2024-03-03T12:50:58Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-03-03T06:56:39Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=110f9db31a2a2b72031292558f7b1d5bab7649c3'/>
<id>urn:sha1:110f9db31a2a2b72031292558f7b1d5bab7649c3</id>
<content type='text'>
When a HTML form is converted to JSON by JavaScript using `FormData()`,
`Object.fromEntries()` and `JSON.stringify` the data type is always
`string`. This does not match the Go struct definitions using multiple
types including e.g. `int`.

There are several options to solve this conflict:

1. use only strings in Go struct definitions
2. write custom functions to parse string-based JSONs to Go structs
3. implement custom functions in JS to use `number` type if possible

Option 3 seems to be a very clean solution. Nevertheless it is limited
by the fact that JSON anyway has a way more limited type system than Go.
So the types used in Go cannot be used and this would reduce this option
to a variant of option 2.

Option 2 requires significant effort per struct inside the model
package. Every object which is transferred via JSON and serialized into
Go structs would require a second struct definition with string types
and a conversion function. This does not scale.

Thus option 1 seems to be the best fit. The reasons for using types like
`int` or `bool` are:

- less memory consumption than `string` in most cases
- implicit data validation (e.g. enforcing positive numbers with `uint`)
- better compatibility with certain APIs which rely on e.g. `int`

The first argument is not so relevant in this use case. The amount of
required memory is still quite small for servers. Implicit data
validation is a good thing but not enough. There should anyway be
validation method which has to be called on CRUD methods and JSON
deserialization.
</content>
</entry>
<entry>
<title>view: Add edit view for model.Recipe type</title>
<updated>2024-02-15T18:58:03Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-02-13T20:16:44Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=246687318e03fb649c30c4510e264e65b25ec6da'/>
<id>urn:sha1:246687318e03fb649c30c4510e264e65b25ec6da</id>
<content type='text'>
</content>
</entry>
<entry>
<title>view: Implement GET handler for model.Recipe</title>
<updated>2024-02-13T19:26:47Z</updated>
<author>
<name>xengineering</name>
<email>me@xengineering.eu</email>
</author>
<published>2024-02-12T19:33:24Z</published>
<link rel='alternate' type='text/html' href='https://cgit.xengineering.eu/ceres/commit/?id=bf0ad86df2e64191f6c430c328fee211ac3affa7'/>
<id>urn:sha1:bf0ad86df2e64191f6c430c328fee211ac3affa7</id>
<content type='text'>
</content>
</entry>
</feed>
