简体   繁体   中英

How can I return JSON with HTTP code in Vibe.d?

I would like to return not only JSON, but also the HTTP response code.

I registering REST interface through URLRouter:

router.registerRestInterface(new ClientServerAPI);

Example of my REST implementation:

module clienserverapi.clientserver;

import api.clientserver;
import models.replies.client_versions;

/**
    Implementation of Client-Server API.
*/
class ClientServerAPI : IClientServerAPI {
@safe:
    ClientVersions getSupportedClientVersions() {
        bool[string] unstableFeatures;
        return ClientVersions(supportedVersions.dup, unstableFeatures);
    }
}

In the REST interface generator the response codes are handled automatically and as you can't pass in a HTTPServerResponse/HTTPServerRequest argument into your REST methods, you can't control what status gets returned.

However there are some built-in statuses which get handled:

  • 200/204 are returned based on content
  • 400 Bad request for mismatched arguments
  • 404 Not found for unmatched routes
  • 500 internal server error is returned on most exceptions
  • (outside of debug mode) unauthorized / bad request / forbidden are sent

See also: REST interface documentation

and you can control any status code using HTTPStatusException , however it is treated as error and will result in a predefined error json which has statusMessage as exception message set and returns the HTTP status code you pass to it. (this is probably what you want for error handling)

You can also change what the errors look like by setting the errorHandler to a RestErrorHandler delegate in your RestInterfaceSettings .

Alternatively, depending on what you want to do, you can use a WebInterface which is a lot like a rest interface, but doesn't have some convenience functions REST interfaces do, but instead can fully access the request/response arguments and can basically do anything like a normal http route and has some other convenience functions you can use.

In theory you could abuse the errorHandler + HTTPStatusException with valid HTTP status codes if you want to return custom success codes with your data, but I would discourage that and instead go with web interfaces if that's what you are after.

However if all you want to do is having custom error codes with a custom, but consistent, error page then I would definitely go with REST interface with an errorHandler.

Your could could now look like this:

import vibe.vibe;
import std.uni;

@safe:

void main() {
    auto server = new HTTPServerSettings;
    server.port = 3000;
    server.bindAddresses = ["::1", "127.0.0.1"];
    auto router = new URLRouter;

    RestInterfaceSettings settings = new RestInterfaceSettings();
    // this is how the error page will look on any thrown exception (like HTTPStatusException)
    settings.errorHandler = (HTTPServerRequest req, HTTPServerResponse res,
            RestErrorInformation error) @safe {
        res.writeJsonBody([
            // design this however you like
            "ok": Json(false),
            "error": serializeToJson([
                "status": Json(cast(int)error.statusCode),
                "message": Json(error.exception.msg),
                "parent": Json("/api/something")
            ])
        ]);
    };
    router.registerRestInterface(new Impl, settings);

    listenHTTP(server, router);
    runApplication();
}

interface RestAPI {
    string getGreeting(string name);
}

class Impl : RestAPI {
    string getGreeting(string name)
    {
        // throw an HTTP Bad Request error when name is empty
        if (name.length == 0)
            throw new HTTPStatusException(HTTPStatus.badRequest, "Name parameter cannot be empty!");
        // throw an HTTP Conflict error code when name is Bob
        if (sicmp(name, "bob") == 0)
            throw new HTTPStatusException(HTTPStatus.conflict, "Server cannot greet Bob!");
        return "Hello, " ~ name ~ "!";
    }
}

and your server will then respond something like:

{
    "ok": false,
    "error": {
        "message": "Server cannot greet Bob!",
        "status": 409,
        "parent": "/api/something"
    }
}

You can try hunt framework, sample code for Rest api:

module app.controller.myapi;

import hunt.framework;

import app.message.UserMessage;

class MyapiController : Controller
{
    mixin MakeController;

    @Action
    JsonResponse test()
    {
        UserMessage user;
        user.id = 1;
        user.name = "MyName";
        user.email = "test@domain.com";

        return new JsonResponse(user);
    }
}

Your response struct:

module app.message.ResultMessage;

struct UserMessage
{
    int id;
    string name;
    string email;
}

Response result is:

[ "id": 1, "name": "MyName", "email": "test@domain.com" ]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM