IR
irwinrodriguez.dev
Back to docs

Quickstart

From zero to a serving endpoint, in seven steps. Every output here is copied from a real run, not written from memory. Valid for FoxServer 0.9.38.

The CLI speaks Spanish today, so its output below is in Spanish. The commands and the exit codes are the same in any language.

Before you start

  • Visual FoxPro 9 SP2. It is your code that gets published: FoxServer translates nothing.
  • FoxServer 0.9.38 installed and licensed. The installer leaves bin\ (the host), cli\ (the command line) and ide\ (the workshop). See Installation.
  • An elevated console, and only for step 4. Without one, that command exits with 17 and touches nothing.
  • curl, which Windows already ships, or any HTTP client.

If you use the CLI from an installation you do not have to configure anything: it finds the workshop and the host by looking at its own feet (<root>\ide\providers\web and <root>\bin\), wherever the root is. With a standalone CLI, set FOXSERVER_TOOLING once.

Two things worth understanding first

Your code stays yours. It only gets published.

A PROCEDURE of a VFP class becomes an HTTP endpoint by declaring a HELP clause. There is no framework to learn and no architecture to change.

pHola: a PROCEDURE published as an endpoint
PROCEDURE pHola(req, res) HELP "GET: hola public"
    RETURN THIS.Ok(THIS.NewObject("mensaje"))
ENDPROC

The route does not exist until you compile.

The route is born in that HELP clause and only reaches the server when the hook extracts it during the build. It is the number one cause of "I added the endpoint and I get a 404". If you add a route and it does not show up: you have not compiled.

1. Create the project

The CLI lives in cli\foxserver.exe of the installation. This command leaves the folder tree, the .pjx and the server manifest in build\.

foxserver init --name Almacen --path C:\proyectos\almacen --port 8099 --format json
{
  "created": true,
  "name": "Almacen",
  "path": "C:\\proyectos\\almacen\\"
}

Note that the manifest exists before anything is compiled: that is what makes the query commands work from here on.

2. Add a controller

It writes the .prg and links it into the .pjx. It is idempotent: over an existing one it exits 0 with a warning, without overwriting the contents.

foxserver controller-add --project C:\proyectos\almacen --name Articulos --format json
{
  "created": true,
  "controller": "Articulos",
  "file": "C:\\proyectos\\almacen\\src\\controllers\\Articulos.prg"
}

If the file is created but does not get linked, it exits with 14: a controller that is not in the project does not exist as far as the server is concerned.

3. Add an endpoint

This writes into the source a procedure with its HELP clause, which is what creates the route. Open it: inside is a VFP class that inherits from ApiController.

foxserver endpoint-add --project C:\proyectos\almacen --controller Articulos `
                      --method get --route articulos --proc pArticulos --public --format json
{
  "created": true,
  "controller": "Articulos",
  "method": "GET",
  "route": "articulos",
  "proc": "pArticulos",
  "public": true
}
ArticulosController: what endpoint-add writes
DEFINE CLASS ArticulosController AS ApiController OLEPUBLIC

    PROCEDURE pArticulos(req, res) HELP "GET: articulos public"
        LOCAL loRes
        loRes = THIS.NewObject("status,data,message")
        loRes.status  = "ok"
        loRes.data    = NULL
        loRes.message = "ok"
        res.status(200).json(THIS.ToJson(loRes))
    ENDPROC

ENDDEFINE

The HELP clause reads like this: "<VERB>: <route> [public]". With public, the endpoint needs no token. And one warning that saves an afternoon: the HELP clause cannot exceed 255 characters. At 256, VFP will not compile and the error does not mention the length anywhere.

This is where everybody gets confused. Run endpoint-list now and it returns []. info will say "endpoints": 0 and openapi will say "paths": []. It is not broken: the endpoint lives in the source and does not reach the manifest until the hook extracts it at compile time. Go on to step 4.

4. Compile - the only wall

foxserver build --project C:\proyectos\almacen --format json

From a normal console this will not work, and that is on purpose. This is what you get:

foxserver: hace falta una consola ELEVADA para compilar.

  BUILD MTDLL registra la coclase en COM al terminar, y sin
  permisos falla con el error 1640 dejando una DLL sin type
  library. Compila, pesa una decima parte y el motor no puede
  activar nada de ella.

  No se ha tocado nada. Abre una consola como administrador y
  repite el comando.

Exit 17, and it touched nothing. Open PowerShell as administrator and repeat it. A build.register warning at the end is not a failure: the DLL is compiled and the exit code is 0.

Now the endpoint does exist for the server:

foxserver endpoint-list --project C:\proyectos\almacen --format json

5. Serve

It starts and returns, giving you the pid. It does not block unless you pass --attach. To stop it, kill that PID.

foxserver serve --project C:\proyectos\almacen --format json

6. Try it

curl http://127.0.0.1:8099/articulos
If you get a 403 and not a 200, it is not your endpoint: it is the license. A Developer license only accepts requests from 127.0.0.1. From another machine you need a Runtime one.

7. And when you want it to be part of the installation

serve serves from the project: it starts the host pointing at the project's build\ folder and touches nothing in the installation. That is fine for testing, but verify.cmd does not see that server and the Windows service does not start it, because both look at the root's config\servers\.

foxserver deploy --project C:\proyectos\almacen
Desplegado Almacen en la instalacion:
  C:\Program Files\FoxServer\config\servers\ALMACEN.json
  clave: 127.0.0.1:8099:

It checks before writing that there is no other manifest with the same host:port:prefix key: if there is, it exits with 11 and says which one, because the host would start one and skip the other with a warning that is only visible in the log. --force skips the check.

The alternative without a command line. All of the above can be done from FoxForge, the workshop the installer leaves in ide\ and which opens with foxforge.cmd inside the Visual FoxPro 9 IDE: menu New › Web service / REST API. It does the same as init, controller-add and endpoint-add, with forms instead of commands. There is a step-by-step tutorial from the IDE.

Checking without starting anything

These work from step 1, with the project uncompiled:

foxserver doctor          --project C:\proyectos\almacen    # que le falta y por donde se expone
foxserver validate        --project C:\proyectos\almacen    # exit 11 si hay errores
foxserver info            --project C:\proyectos\almacen --format json
foxserver openapi         --project C:\proyectos\almacen    # el contrato, sin levantar el servidor
foxserver middleware-list --project C:\proyectos\almacen    # auth, logging, status, sse...

If something goes wrong

ExitWhat happenedWhat to do
2A required argument is missing, or an enum value is not validfoxserver describe gives you the exact schema
10There is no manifest in build\That folder is not a FoxServer project. It is not "you have not compiled": the manifest is created by init
11The project has validation errorsfoxserver validate lists them with their severity
12The FoxForge tooling is missingUse the CLI from an installation, or set FOXSERVER_TOOLING
13vfp9.exe not found--vfp <path> or FOXSERVER_VFP
14The write failedCheck whether the .prg got linked into the .pjx
16FoxServer.Host.exe not foundUse the CLI from an installation, or --host <path>
17build without an elevated consoleOpen one as administrator
18The compilation failedThe errors come out on stderr, with file and line, from VFP's .ERR. If there was a previous MTDLL it is still standing: the server would be serving the old code

Next steps