--- title: joyce - record your thoughts as they come author: Federico Igne date: \today --- `joyce` is an attempt at building a tool for rapid notetaking, i.e., quick collection of short thoughts that can come to mind at any point. On a high-level, this system should be: - *Hubiquitous*, needs to be available (read/write) whenever one has internet connection (falling back to pen&paper, otherwise). - *Searchable*, one has to be able to search and filter the pile of notes. - *Out of the way*, sophistication will only get in the way of recording one's thoughts. `joyce` is structured as a small tool written in Rust running on a server, loosely inspired by [`twtxt`](https://github.com/buckket/twtxt). Clients interface themselves with the server through a simple REST API. # Notes Notes are the first-class citizen of `joyce` and are the main content exchanged between server and clients. Notes, along with their REST API are defined in their own module ```{#main_mods .rust} mod note; ``` ```{#note.rs .rust path="src/"} <> <> <> <> ``` ## Anatomy of a note A *note* is a simple structure recording a timestamp determined at creation, a list of tags, and the body of the note. ```{#note_struct .rust} #[derive(Debug, Deserialize, Serialize)] pub struct Note { timestamp: DateTime, tags: Vec, body: String, } <> ``` ```{#note_impl .rust} impl Note { fn new(body: String, tags: Vec) -> Self { Self { timestamp: Utc::now(), tags, body } } } ``` A set of notes is just a `Vec` of `Note`s. ```{#note_collection .rust} type Notes = Vec; ``` ### (De)serialization Since notes need to be sent and received via HTTP, the structure needs to be *serializable*. ```{#dependencies .toml} serde = { version = "1.0", features = ["derive"] } ``` ```{#note_uses .rust} use serde::{Serialize, Deserialize}; ``` ### Timestamps Timestamps adhere the *RFC 3339 date-time standard* with UTC offset. ```{#dependencies .toml} chrono = { version = "0.4", features = ["serde"] } ``` ```{#note_uses .rust} use chrono::prelude::{DateTime, Utc}; ``` # The REST API `joyce` uses [`actix-web`](https://actix.rs/) to handle HTTP requests and responses. ```{#dependencies .toml} actix-web = "4.1" ``` ## Resources - [Tutorial](https://web.archive.org/web/20220710213947/https://hub.qovery.com/guides/tutorial/create-a-blazingly-fast-api-in-rust-part-1/) - [Introduction to `actix`](https://actix.rs/docs/getting-started/) ## GET /notes Each request handlers is an *async* function that accepts zero or more parameters, extracted from a request (see [`FromRequest`](https://docs.rs/actix-web/latest/actix_web/trait.FromRequest.html) trait), and returns an [`HttpResponse`](https://docs.rs/actix-web/latest/actix_web/struct.HttpResponse.html). Here we are requesting the list of notes currently in the system. The function takes 0 parameters and returns a JSON object. ```{#note_uses .rust} use actix_web::{HttpResponse,get}; use actix_web::http::header::ContentType; ``` ```{#req_get_notes .rust} #[get("/notes")] pub async fn list() -> HttpResponse { let mut notes: Notes = vec![]; <> HttpResponse::Ok() .content_type(ContentType::json()) .json(notes) } ``` # The program The main program is structured as follows ```{#main.rs .rust path="src/"} <> <> <> ``` # Main service The main service will instantiate a new `App` running within a `HttpServer` bound to *localhost* on port 8080. ```{#main_uses .rust} use actix_web::{App, HttpServer}; ``` The `App` will register all request handlers defined above. ```{#main_service .rust} #[actix_web::main] async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new() .service(note::list) }) .bind(("127.0.0.1", 8080))? .run() .await } ``` # Testing ```{#notes_retrieve .rust} notes.push(Note::new( String::from("This is a first test note!"), vec![String::from("test"), String::from("alpha"), String::from("literate")])); notes.push(Note::new( String::from("This is my favourite emoji: 🦥"), vec![String::from("test"), String::from("emoji")])); notes.push(Note::new( String::from("Here is a link: https://www.federicoigne.com/"), vec![String::from("test"), String::from("links")])); ``` # Open questions - Should one be able to delete notes? Or mark them as read/processed? - Authentication method? - Custom filters on retrieval. # Credits `joyce v0.1.0` was created by Federico Igne ([git@federicoigne.com](mailto:git@federicoigne.com)) and available at [`https://git.dyamon.me/projects/joyce`](https://git.dyamon.me/projects/joyce). ```{#Cargo.toml .toml} [package] name = "joyce" version = "0.1.0" edition = "2021" [dependencies] <> ```