How should I architecture an api?

Hey guys, bit of an abstract question. I'm writing a discord bot in php so I can better understand php. This will be a terminal application. I'll also have a portion of the app in python to do sentiment analysis. I was wondering what the heck are the logistics behind writing a way to communicate between the php (bot) portion of the app and the python (sentiment analysis) portion of the app? I'm assuming I can write an api between the 2, but then my question is how do I even host that? I know how apis work but I've never actually set one up myself. I'd be using a digital ocean droplet with cpanel installed, and cpanel comes with apache ootb so I'm assuming i'd need to configure it in apache
16 Replies
Jochem
Jochem•2w ago
that's a bit of a complicated one with the addition of it being a bot. I'm not 100% sure how discord bots work, they run non-stop right? normally, an API is just a bunch of endpoints, which in simple, vanilla PHP are really nothing more than a bunch of files on disk that get an HTTP request with a certain HTTP verb pointed a them, run, fetch or modify the database, and then return a (usually) JSON response on a technical level, there's really no difference between a php file that outputs HTML for the browser or one that outputs JSON to be consumed by a different application. Apache doesn't care which its serving, so there's nothing to configure there
vince
vince•2w ago
Yea they do. I think the github readme even says it might not be possible to configure it on a webserver but there has to be some way to host it. I don't believe that the big discord bots are running on someone's own computer constantly lol but i can figure that part out. And for the second point with the api being endpoints, I get that part. But I'm not sure I understand your second part about the files. You're saying that each endpoint is just a file, but then how do I configure my webserver to handle those requests? Is it literally just as simple as naming it something like endpoint.php and if I do something like fetch(/endpoint.php) (using js here since that's what I know), it'll work?
Jochem
Jochem•2w ago
yeah, pretty much PHP uses file based routing by default, same as plain HTML, so any time you put a file somewhere in the webroot of the server, you can reach it using the relative path As for hosting a PHP script that runs continuously, there's ways on Linux to start a PHP file as a daemon, which is really just a call to the process from a non-login shell. The very simplest way though is to run screen or tmux, log in to that, run php bot.php and then detach The issue is that it's not really that easy to then inject stuff into that running process. Calls to your API can fetch data from the same data source, and modify that data, but it's harder to then notify the running process that something has been updated. I'm honestly not sure how you'd do that, short of polling for changes in the running process
Aoi
Aoi•2w ago
Can you really maintain a websocket connection using php?
Jochem
Jochem•2w ago
there's nothing in PHP that prevents it from running continuously I wrote an IRC bot an Age ago that just opened a TCP socket connection and listened to that in a loop
vince
vince•2w ago
Would I have to inject anything though? The discord php library is built on async programming since it's just calling the native discord api. If I just have some event listener to listen for messages, and then feed that message into the api endpoint (that I made) and make a promise to return a boolean, wouldn't that be basically the same thing that the discord php wrapper does with the discord api?
Jochem
Jochem•2w ago
well, the api endpoint as I described it would be a page on a webserver, while a bot that runs continuously would be its own separate process. They have no direct way to communicate (though again, I don't know exactly how the discord bot API works. Just going off of what I know from building that IRC bot dogs years ago)
vince
vince•2w ago
Oh I think I see what you're saying brb meeting Okay I'm back. So you're saying the reason why the approach you mentioned wouldn't work is because it would assume that I have a website in the sense that I've got pages? Sorry if I'm completely off base here lol. Still have a lot to learn
Jochem
Jochem•2w ago
I'll reply properly when I'm back at a keyboard so at its most basic, an API endpoint in PHP might look something like this:
<?php
/*
* Your setup code goes here. Connect to db, for example, any includes...
*/
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
$records = $db->fetchAll();
die(json_encode($records));
break;
case 'POST':
if (!validate($_POST['field'])) {
die(json_encode({status: 400, message: "Validation failed"}));
}
$newrecord = $db->insert($_POST['field']);
die(json_encode($newrecord));
break;
case 'DELETE':
$db->delete($_POST['recordid']);
die(json_encode({status: 200, message: "ok"}));
break;
default:
die(json_encode({status: 400, message: "Bad request"}));
break;
}
<?php
/*
* Your setup code goes here. Connect to db, for example, any includes...
*/
switch ($_SERVER['REQUEST_METHOD']) {
case 'GET':
$records = $db->fetchAll();
die(json_encode($records));
break;
case 'POST':
if (!validate($_POST['field'])) {
die(json_encode({status: 400, message: "Validation failed"}));
}
$newrecord = $db->insert($_POST['field']);
die(json_encode($newrecord));
break;
case 'DELETE':
$db->delete($_POST['recordid']);
die(json_encode({status: 200, message: "ok"}));
break;
default:
die(json_encode({status: 400, message: "Bad request"}));
break;
}
It's semi-pseudo code, and I'm very rusty, but basically it's something that takes parameters in from the HTTP request, and then uses those parameters to do something and return JSON. That could be saved as record.php in your document root, so you could point fetch to https://localhost/record.php and send your request you can make it fancier by returning a documentation message if someone uses a request with the header set to expect an HTML response, set the headers to indicate that the response is in jsonor a dozen other things, but at its core, it's just a PHP file that outputs JSON
vince
vince•2w ago
Thanks Jochem for the detailed response! and it makes sense 🙂. So I'd need 3 components - the terminal app that's hosted on the webserver, an api hosted on the same webserver, and python scripts that take a message as input and returns either true or false, depending on if the message contains a topic. I don't think I'd need a database for this, but I am training a model on input so that could definitely need one... I'm not sure I still 100% understand the pitfalls you're describing so I think the best thing to do is just try it and then come back here and read your messages
Jochem
Jochem•2w ago
and always feel free to ask more when you get stuck 🙂
Hashi
Hashi•2w ago
I couldn’t grasp what you are trying to achieve with the described apps but regarding running “perpetual” php script you might wanna consider defining it as service, in case of system reboot, although not sure how likely that would be to occur 🙂
vince
vince•7d ago
What do you mean by 'defining it as a service'?
Hashi
Hashi•7d ago
Hmm great question, not sure I can explain myself in the most accurate way. A service I would say is something that is running in the background and is meant to run for a long time/perpetually, something that can be set up to boot when your “virtual machine” boots. A more practical answer would be the answer in this stackoverflow question: https://askubuntu.com/questions/1211954/running-a-php-script-at-startup-after-other-services-have-started
Ask Ubuntu
Running a PHP script at startup AFTER other services have started
To get regular weather updates into my Redis database the scheme I am trying to use is as follows I have a PHP script that fetches the weather from the relevant weather API. It goes something lik...
Hashi
Hashi•7d ago
As disclaimer the answer is Ubuntu distros specific.
vince
vince•7d ago
I see, thank you! I'll have to look into this đź‘€ I think I kind of get the gist of what you're saying though