Giter Club home page Giter Club logo

actix-realworld-example-app's Introduction

RealWorld Example App

Actix codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API.

โ— (2021/05/13) This codebase is currently unmaintained, and I am not interested in maintaining it. This relies on an old version of Actix -- developers who want to learn Actix should probably read the latest docs at the Actix website.

This codebase was created to demonstrate a fully fledged fullstack application built with Actix including CRUD operations, authentication, routing, pagination, and more. CORS, however, is not yet added.

This implementation is not reviewed. See the Contributing section below.

For more information on how this works with other frontends, head over to the RealWorld repo.

How it works

This is an application written in Rust that utilizes Actix for developing the backend web service that powers the RealWorld application.

You can view a full list of crates being used in Cargo.toml, but here are some of the main ones of note:

  • Actix - a powerful Actor framework
  • Chrono - a Date and Time library for Rust
  • Failure - a system for creating and managing errors in Rust
  • Futures - Zero-cost Futures in Rust
  • jsonwebtoken - Create and parses JWT (JSON Web Tokens)
  • libreauth - a collection of tools for user authentication
  • Serde - a framework for serializing and deserializing Rust data structures efficiently and generically
  • Uuid - Generate and parse UUIDs
  • validator - Simple validation for Rust structs

Getting started

  • Install Rust
  • Install PostgreSQL if you don't have it already.
  • Install the Diesel CLI with the postgres feature enabled.
  • Clone this repo to a folder on your computer.
  • Copy (cp) .env.example to .env within this directory, and change the environment variables accordingly to your system.
  • Setup your database by running diesel database setup. Make sure it has completed successfully.
  • Build this project with cargo build. You are welcome to compile with --release if you'd like.
  • Run with cargo run.
  • The API URL will be whatever the BIND_ADDRESS value is in .env with the /api path included e.g. https://127.0.0.1:3000/api. Set it as such in your REST client (Postman, Insomnia, etc.), import the postman collection and start testing it out!

Contributing

Feel free to take a look at the current issues in this repo for anything that currently needs to be worked on.

You are also welcome to open a new issue if you see something is missing or could be improved upon.

actix-realworld-example-app's People

Contributors

fairingrey avatar geropl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

actix-realworld-example-app's Issues

Actix server + DNS

Hello.

I've been scouring for a solution to this, but I can't seem to find one. Maybe I'm understanding this wrong cause I'm pretty new to rust.

How could I connect the actix server to a dns? As it is at the moment it seems that the only way to access the server's api is through an application running on the same machine.

Authentication logic

I think would be better to handle authentication as middleware of a base route, I think wrap can do the job in actix.

Feel free to criticize this idea considering that I'm not an actix expert! ๐Ÿ™‚

Visiting localhost/api via browser causes threads to panic.

Just downloaded/set it up to try it out.
Any idea what's causing this?

thread 'arbiter:ed63170e-3426-4aaa-bbb5-2ccfbfb2147a:actix-net-worker-3' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:4c9e2b97-7110-42c1-8fe1-abb61979e105:actix-net-worker-4' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:c3b18044-efe3-49da-8978-3af67764e026:actix-net-worker-11' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:d4df4aae-37c6-4a75-af6e-c3426a11fb78:actix-net-worker-8' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:7f6bb722-363b-40cd-8788-bc02f2806eee:actix-net-worker-9' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:aa2b968a-40f0-4d85-8ace-7653ba749b29:actix-net-worker-7' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:96bb52d2-f4f1-46bb-857c-2a5ee7949153:actix-net-worker-2' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5
thread 'arbiter:882e27d2-d090-4ab0-9b78-e5f76497d71f:actix-net-worker-10' panicked at 'Failed to create pool.: InternalServerError', src/libcore/result.rs:997:5

error - "cargo build"

when i do cargo build this error comes up. What is it ?

ubuntu@ubuntu:~/rust/projektx$ cargo build Compiling conduit v0.1.0 (/home/ubuntu/rust/projektx) error[E0277]: the trait bound uuid::Uuid: diesel::Expressionis not satisfied --> src/models/article.rs:18:17 | 18 | #[derive(Debug, Insertable)] | ^^^^^^^^^^ the traitdiesel::Expressionis not implemented foruuid::Uuid| = note: required because of the requirements on the impl ofdiesel::expression::AsExpressiondiesel::sql_types::Uuidforuuid::Uuid`
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article.rs:18:17
|
18 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article.rs:38:17
|
38 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article.rs:38:17
|
38 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article_tag.rs:15:17
|
15 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article_tag.rs:15:17
|
15 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/comment.rs:16:17
|
16 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/comment.rs:16:17
|
16 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/follower.rs:15:17
|
15 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/follower.rs:15:17
|
15 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article.rs:18:17
|
18 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &'insert uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &'insert uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article.rs:38:17
|
38 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &'insert uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &'insert uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/article_tag.rs:15:17
|
15 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &'insert uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &'insert uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/comment.rs:16:17
|
16 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &'insert uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &'insert uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound uuid::Uuid: diesel::Expression is not satisfied
--> src/models/follower.rs:15:17
|
15 | #[derive(Debug, Insertable)]
| ^^^^^^^^^^ the trait diesel::Expression is not implemented for uuid::Uuid
|
= note: required because of the requirements on the impl of diesel::Expression for &'insert uuid::Uuid
= note: required because of the requirements on the impl of diesel::expression::AsExpression<diesel::sql_types::Uuid> for &'insert uuid::Uuid
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 15 previous errors

For more information about this error, try rustc --explain E0277.
error: could not compile conduit.

To learn more, run the command again with --verbose.
ubuntu@ubuntu:~/rust/projektx$
`

Question about routes

Looking at all the RealWorld examples, I did not find much in the way of talking about how to use it, I understand it is a larger picture app, meant to look the same in any language, but a few notes would help some new to RealWorld to get started.

This is on the front end
https://thinkster.io/tutorials/fullstack/building-the-frontend

The API:
https://github.com/gothinkster/realworld/tree/master/api

With no documents, I have no idea what to expect from the back end, but I am interested.
Looking at the code the project looks great.

Thanks @fairingrey.

Upgrade to latest actix-web and try proc macro way

Hello guys and thank you so much for the real world app example. I will use it ๐Ÿ˜„

I was just thinking , do you think it could be possible to update it to the latest actix-web and maybe try with the proc_macro way of doing ?

I tried it on my own app but I am not sure about the proc/cons for traditional way to write handlers vs proc_macro way.

What do you think ? Should we try to make a real world example this way as well to see the pros and cons ?

Best regards,
Arn

Write proper unit tests and integration tests

Related: #19

IMHO, one of the major deficiencies of actix-web documentation and codebase is that examples may not be self-contained, being clean enough and straighforward enough for newcomers into the library. By "self contained" I mean: "copy from the browser, paste into two files: Cargo.toml and main.rs ... fire cargo and it works."

Writing an end-to-end, real world application, containing reasonable unit tests and integration tests would potentially eradicate this deficiency.

Also, since Actix 2.0 now employs async/await, several examples from the documentation website are just outdated and so, if you are a newbie and copy/paste the example... it will take you a number of hours until you realise that you were simply misguided.

In my case in particular, I've struggled a lot to write a proof of concept which looks like code in production. Examples in the documentation are incomplete (they are just snippets of code), not exercising real world scenarios, which render them sometimes almost useless... apart from the syntax they introduce or some mechanics they illustrate.

I had difficulties finding an example which "just works", which does something so mundane: a simple client code (using actix-web client, not anything else!) which sends a post request containing some JSON and receives some other JSON as response. There's no such example containing unit tests and integration tests (which just work!) as far as I know and, in order to build one, I had to invest a lot of time and effort digging into the code base of a number of repositories.

Then, finally the coin dropped after a number of hours: it does not work because I'm using Actix 2.0 but trying documentation from the website which assumes Actix 1.0.

So, once again: Writing proper unit tests and integration tests in a context of a real world application is a must. Ideally, employing Actix 2.0 as #19 suggests.

migrate to actix-web 1.0

With the release of actix-web 1.0 (a major point release!), this repo should be migrated to use the updated dependency.

actix 2.0 upgrade?

Any planning for actix 2.0? I think as async await is released its a good time to update it and see how ergonomic actix is for realworld example app.

Errors seem to require a special JSON format

Errors seem to require a special JSON format, detailed here in the API spec: https://github.com/gothinkster/realworld/tree/master/api#errors-and-status-codes

{
  "errors":{
    "body": [
      "can't be empty"
    ]
  }
}

This is the file where custom errors are generated, so we'll have to make some changes here such that .json(message) takes in a proper object that can be serialized in such a format. More info on that function can be found here, but it takes in a type that impl's Serialize.

FWIW, validation errors does not currently offer any default implementation of Serde's Serialize so we'll have to implement it on our own as described at https://serde.rs/impl-serialize.html or use an existing type that they provide (see my comment below).

Set up a proper integration pipeline

https://github.com/fairingrey/actix-realworld-example-app/blob/master/.travis.yml is actually pretty scarce at the moment. All it does is run cargo check --verbose on the codebase to see if there are any syntax errors.

The idea later is that we should perform some sort of database dump (probably pg_dump to .sql), see that Travis imports the db into their box, run the backend application on their machine, run tests against it, and then gracefully shutdown after all tests have hopefully passed.

Will heavy database query make one of cpu cores idle?

Hi, I'm trying to figure this out, since apparently diesel doesn't support async (nor underlying postgres driver).

You're not explicitly specifying number of workers for HttpServer, which means it will create (number of cpu cores)-threads for handling incoming http requests.

Now, when next http request runs heavy database query through diesel it will block current thread. And for example, if my system has 4 cpu cores, it's enough to run 4 heavy http requests simultaneously to completely DoS entire server.

Is that correct?

Unit Testing

AFAIK there isn't any idiomatic way I know of to do unit testing in an actix-web application, as that would involve having to mock client messages on valid data, and given handlers are async ('technically' speaking, as the db actor is still sync) this might prove to be a bit difficult...

If anyone has suggestions or ways to approach this issue, feel free to make a comment or open a PR. Otherwise I'll try looking around and see what other people are doing before I attempt to make a test suite myself.

error when run `cargo run`

when i run cargo run it appears an error
"thread 'main' panicked at 'Failed to create pool.: InternalServerError', src/app/mod.rs:31:25"
what is it? how to fix it? I'm a beginner to using Rust.
thanks.

The authorization would better be a middleware wrapped

example

App::new() .register_data(Data::new(state)) .wrap(Logger::default()) .wrap(cors) .wrap(crate::middleware::authen_middleware::Authentication) .configure(routes) }) .bind(&bind_address) .unwrap_or_else(|_| panic!("Could not bind server to address {}", &bind_address)) .start();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.