DEV Community

Pierre Bouillon
Pierre Bouillon

Posted on

Minimal API in c

Hi !

I recently started to explore the possibilities of creating my own API and so far, it is pretty much simple in Python and C#; that's why I wanted to dive a little deeper in it and try to create my own in C.

The problem is that it seems that I can't find any accessible and minimalist implementation of an API in C (with its basic concepts, such as socket for example).

Could anyone show me / link me a resource that would explain me how to do a small hello world for example (as flask does) ?

Thank you !

Top comments (10)

Collapse
 
phlash profile image
Phil Ashby

Since you haven't specified what sort of API you are interested in, I've taken the liberty of assuming a simple line-based protocol (request/response) in this example, most higher layer textual protocols such as HTTP/SMTP/NNTP/IMAP/etc. are built on top of plain lines of text:

// Trivial line-based network API in C
// Phlash, 2019
// Save as: netapi.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// It went wrong - try to print a descriptive error and bail out
int barf(char *msg) {
        perror(msg);
        return 1;
}

int main(int argc, char **argv) {
        int list, sess, size, port = 9000;
        struct sockaddr_in addr;

        if (argc > 1)
                port = atoi(argv[1]);

        list = socket(PF_INET, SOCK_STREAM, 0);
        if (list<0)
                return barf("creating socket");

        addr.sin_family = AF_INET;
        // NB: listens on all interfaces and is accessible from off the machine - beware!
        addr.sin_addr.s_addr = INADDR_ANY;
        addr.sin_port = htons(port);
        if (bind(list, (struct sockaddr *)&addr, sizeof(addr)) < 0)
                return barf("binding to port");
        listen(list, 1);

        printf("waiting for connection on port: %d\n", port);
        size = sizeof(addr);
        while ((sess = accept(list, (struct sockaddr *)&addr, &size)) > 0) {
                // Here we open the raw socket as a stdio FILE so we can use fgets() / fprintf()
                FILE *fp = fdopen(sess, "r+");
                char buf[1024];
                printf("connection from %s, reading a line of input\n", inet_ntoa(addr.sin_addr));
                // Our made up protocol says hello and waits for text
                fprintf(fp, "200 hello, type stuff!\n\r");
                // because stdio is buffered, we flush to ensure our message gets out
                fflush(fp);
                // now we read a line of text terminated by \n
                if (fgets(buf, sizeof(buf), fp) == NULL)
                        return barf("reading input");
                printf("responding\n", buf);
                // echo the text back with some made up protocol bits
                fprintf(fp, "250 message received:\n\r%s200 OK\n\r", buf);
                fflush(fp);
                // we could continue reading/writing but this is an example :)
                fclose(fp);
                size = sizeof(addr);
        }
        return 0;
}

This 'works for me' on my local machine, compiled with vanilla gcc:

$ gcc -o netapi netapi.c
$ ./netapi

then in another terminal:

$ telnet localhost 9000

Enjoy :)

Collapse
 
pbouillon profile image
Pierre Bouillon

Thank you so much !

I will build my researches around this, thank you for your time !!

Collapse
 
phlash profile image
Phil Ashby

You're welcome - there are a few things I would say about writing network services in C, and particularly on unix-like systems:

  • memory management will be a PITA as soon as you want to do anything complex (there is already a 1024 byte buffer in this example!)
  • look at the inetd way of doing this - it manages networking and sub programs provide protocol handling via stdio, use the pipes Luke :)
  • have a go at turning the example into an HTTP/0.9 server (no request headers, just the request line to parse), if you feel brave look at adding handler threads with pthreads... then never expose to the 'net as pretty much all C network code has vulnerabilities, especially mine!

Have fun!

Collapse
 
fquinner profile image
fquinner

Does it need to use socket? Even for C programming, writing an API using sockets can soon become non-portable and painful. I'd suggest using something like mongoose for C or Poco if you can stretch to C++ (the "other" poco if you're coming from C# ;)). The poco project has a hello world style web app example right on it's home page.

Collapse
 
pbouillon profile image
Pierre Bouillon

I would absolutely love to. Unfortunately it seems that "try it the way we teach it" instead of "do it in the most elegant way or with the most relevant tools" is not a very common practice in CS here 😭

Collapse
 
grantstromgren profile image
Grant Stromgren

I ended up going with a C# API in one of my projects, more so out of it's ease of authentication/authorization with Active Directory.

I found the .NET Web API framework really easy to use, but as Meghan mentioned, nothing is too "minimal" around here.

Collapse
 
nektro profile image
Meghan (she/her)

Nothing in C is minimalist.

Collapse
 
pbouillon profile image
Pierre Bouillon

True ahah

Collapse
 
joruch profile image
Joris

This is maybe a little of topic. But Ms build a really powerful rest framework in cpp. Maybe you can draw some inspiration from there

Collapse
 
pbouillon profile image
Pierre Bouillon

I will give it a look, thanks !