DEV Community

Cover image for Rapidly build your own stateless REST-API with neoan3
neoan
neoan

Posted on • Originally published at blua.blue

Rapidly build your own stateless REST-API with neoan3

Coding along should approx. take you 15 min

What we will be working on:

  • Setup
  • Adding a simple model
  • Writing authentication endpoints
  • Final thoughts

Setup

Since we don't want to spend a lot of time on addressing various environments, let's check out the official docker setup for neoan3:

git clone https://github.com/neoan3/docker.git

Our only constraint is the need for docker-compose, so be sure you have that installed (comes with Docker Desktop on Mac & Windows). In order to get started, we will run the following commands:

docker-compose up -d --build

docker-compose exec neoan3 sh

That's it! The hashtag you will see indicates you are executing the service's shell as root.

From here, let's finally get started and create a neoan3 project:

neoan3 new app

To verify everything works as expected, try visiting http://localhost:8090

Image description

Adding a simple user model

The easiest way to get fast results is to use the basic email login.

neoan3 add model https://github.com/neoan3/email-password-auth.git

Later, it makes sense to look at the few lines of relevant code in the folder model/user , but for now we will jump over to migrating the model with our database that shipped with our docker setup. To do so, all you need it to run

neoan3 migrate models up and then choose neoan3_db as the credential key.

To verify the installation of our model has worked as expected, visit http://localhost:8090/migrate and see if you can find "user" in the dropdown.

NOTE: Don't worry about the security-warning you will see on that page. This is just a reminder that you shouldn't deploy this setup without taking the steps lined out in the README of the docker repo we started out with.

Writing authentication endpoints

Let's finally code something, right? Well, almost. Let's get us started with some boilerplate for our endpoints:

neoan3 new component auth -t:api -f:demo

This command will get us to a good starting point and within your project you should find a folder [app]/component/Auth with a file AuthController.php. And that's the file we will work with.

The plan

We want to have the following endpoints at our disposal

  • POST /auth (this is our login-endpoint)
  • POST /auth/register (this is, well, you guessed right)
  • GET /auth (this returns a logged in user or a 401 unauthorized response. We mainly want that for testing.)

FYI: the default api-endpoint behavior is using neoan3 api v1. Our endpoints will therefore be at http://localhost:8090/api.v1/auth### Let's first look at the method postAuth

Since we want both /auth and /auth/register to be handles by this method, our postAuth should look like this:

function postAuth(string $mode = 'Login', array $body=[]): array
{
    if($mode === 'Login'){
        // for endpoint /auth (or /auth/login)
    }
    if($mode === 'Register'){
        // for endpoint /auth/register
    }
    return [];
}
Enter fullscreen mode Exit fullscreen mode

As you can see, the API converts kebab-case to PascalCase, so something like /auth/log-me-in would be interpreted as LogMeIn.

adding model transactions

We are using PHP8 in our docker setup. This makes it possible to load injections via Attribute
My IDE does most of this for me, but be sure to have both
use Neoan3\Provider\Model\InitModel; and
use Neoan3\Model\User\UserModel; after the namespace of your file

// 1. Load our user model
#[InitModel(UserModel::class)]
function postAuth(string $mode = 'Login', array $body=[]): array
{
    // 2. pass the payload (body) to the corresponding model-method
    if($mode === 'Login'){
        // for endpoint /auth (or /auth/login): send the credentials to login
        $user = UserModel::login($body);
    }
    if($mode === 'Register'){
        // for endpoint /auth/register: send the credentials to register
        $user = UserModel::register($body);
    }
    // 3. create a JWT token
    $auth = $this->provider['auth']->assign($user['id'], ['user','self'], $user);
    return ['token' => $auth->getToken()];
}
Enter fullscreen mode Exit fullscreen mode

GET /auth

In order to try this out without a front-end we can use neoan3's on-board helper located at http://localhost:8090/endpoint

But first, let's built our GET-method. The most basic usage would be to restrict access to our GET-endpoint unless authenticated:


// 1. Add the authorization Attribute
#[Authorization('restrict')]
function getAuth(): array
{
    // 2. read the JWT
    $auth = $this->provider['auth']->validate();
    // 3. return its content to the client without exposing the identifier
    return $auth->getPayload();
}
Enter fullscreen mode Exit fullscreen mode

Now we can jump over to http://localhost:8090/endpoint and start with our test-scenario:

  1. Creating a user:

Set the endpoint to "auth/register" with the method POST, adding a JSON-payload like
{"email":"test@example.com","password":"secure-me"}

When hitting send you should get an answer with a token

  1. Test authentication

Copy the content of the token and paste it into the input field at the authorization-tab, then switch the method to GET after setting the endpoint to auth.

You should now receive your user back.
endpoint

Final thoughts

First of all: did you run in any kind of issues? Let me know. Otherwise, I hope you are able to derive how easy it is to work with persistent data with neoan3 beyond a user model. Lastly, let's talk about CORS.
I don't know what your plans for the frontend are. Whenever you get into a scenario where you run your application outside of the docker container (e.g. while developing a VueJS app), you will likely have a development server with a port (e.g. 8080). In order to work with cross-origin requests, please find the file default.php and adjust the allowed_origins accordingly (wildcard works, but be aware of the implications)

Happy coding

Top comments (0)