REST

salesforce 的 REST API 是通过 annotation 的方式来暴露给外部调用的

同步请求最大 6M,异步请求最大 12M

在 class 上注解 @RestResource 来将其公开为 REST 资源

  • 相对路径 /services/apexrest/
  • 可以使用 * 通配符
  • 区分大小写
  • 必须使用 global 关键词

在 method 上注解 @HttpGet @HttpPost 等来将其公开为可以通过 HTTP GET 或 POST 请求的资源

@RestResource(urlMapping='/yourUrl')
@HttpDelete
@HttpGet
@HttpPatch
@HttpPost
@HttpPut

需要新建 连接的应用程序

  • 设置 -> 创建 -> 应用程序(左侧导航)
  • 最下方(连接的应用程序)-> 新建
  • 填写相关的信息,需要启用 OAuth 设置 -> 保存
  • 点击管理可以设置 IP 限制等
  • 点击名称可以看到 client_id 和 client_secret
  • 配置会话超时时间

左侧搜索 会话设置

  • 设置会话超时值,跟应用程序的会话超时值一致

站点设置

有些场景,需要让第三方平台回调我们的 SF REST API,但是不能要求第三方做登录操作,可以设置站点来提供无需登录的接口服务。

  • 应用程序设置 -> 开发 -> 站点 -> 新建 -> 填写相关内容(启用站点主页可选SiteLogin)
  • 新建完站点后 -> 公开访问设置 -> 已启用 Apex 类访问权限 -> 设置需要公开访问的 APEX 类
  • 需要将类设置成 without sharing

salesforce API

/**********************************************************************
 * 
 *
 * @url: /services/apexrest/book
 * @data:
 *  {

    }
*************************************************************************/

@RestResource(urlMapping='/book/*')
global with sharing class BookREST {

    @HttpPost
    global static String doPost(BookPostData data) {
        Book__c book = new Book__c();
        book.Name = data.name;
        book.Price__c = data.price;
        insert book;
        return book.id;
    }

    @HttpDelete
    global static Boolean doDelete() {
        RestRequest req = RestContext.request;
        // RestResponse res = RestContext.response;
        String id = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
        Book__c book = [SELECT Id FROM Book__c WHERE Id = :id];
        delete book;
        return true;
    }

    @HttpPatch
    global static Boolean doPatch(BookPostData data) {
        Book__c book = [SELECT Id,Name,Price__c FROM Book__c WHERE Id = : data.id];
        book.Name = data.name;
        book.Price__c = data.price;
        update book;
        return true;
    }

    @HttpGet
    global static Book__c doGet() {
        RestRequest req = RestContext.request;
        String id = req.requestURI.substring(req.requestURI.lastIndexOf('/')+1);
        Book__c book = [SELECT Id FROM Book__c WHERE Id = :id];
        return book;
    }

    global class BookPostData {
        public String name;
        public Decimal price;
        public String id;
    }

}

PHP请求API

namespace App\Services;

use App\Com\Json;
use GuzzleHttp\Client;
use phpDocumentor\Reflection\Types\Context;
use Psr\Http\Message\ResponseInterface;

class SalesForceService
{

    protected $grantType;

    protected $clientId;

    protected $clientSecret;

    protected $userName;

    protected $password;

    protected $loginUrl;

    protected $instanceUrl;

    protected $client;

    public function __construct()
    {
        $this->grantType = env("SALESFORCE_GRANT_TYPE");

        $this->clientId = env("SALESFORCE_CLIENT_ID");

        $this->clientSecret = env("SALESFORCE_CLIENT_SECRET");

        $this->userName = env("SALESFORCE_USERNAME");

        $this->password = env("SALESFORCE_PASSWORD");

        $this->loginUrl = env("SALESFORCE_LOGIN_URL");

        $this->instanceUrl = env("SALESFORCE_INSTANCE_URL") . "services/apexrest/";

        $this->client = new Client();
    }


    public function getToken()
    {
        try {

            // TODO 读取 redis 缓存

            $options = [
                'grant_type' => $this->grantType,
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'username' => $this->userName,
                'password' => $this->password
            ];

            $url = $this->loginUrl . 'services/oauth2/token';

            $response = $this->client->request('post', $url, [
                'form_params' => $options
            ]);

            $response = $this->processResponse($response);

            if (!empty($response['access_token'])) {
                // TODO redis 缓存 token
                return $response['access_token'];
            }

            return '';

        } catch (\Throwable $e) {
            // TODO LOG
        }


        return '';
    }

    public function post($uri, $token, $params)
    {
        try {

            $url = $this->instanceUrl . $uri;

            $response = $this->client->request("post", $url, [
                'headers' => [
                    'Authorization' => "Bearer {$token}"
                ],
                'json' => $params,
            ]);

            return $this->processResponse($response);

        } catch (\Throwable $e) {
            // TODO
        }

        return '';
    }

    public function delete($uri, $token)
    {
        try {

            $url = $this->instanceUrl . $uri;

            $response = $this->client->request("delete", $url, [
                'headers' => [
                    'Authorization' => "Bearer {$token}"
                ]
            ]);

            return $this->processResponse($response);

        } catch (\Throwable $e) {
            // TODO
        }

        return false;
    }

    public function patch($uri, $token, $params)
    {
        try {

            $url = $this->instanceUrl . $uri;

            $response = $this->client->request("patch", $url, [
                'headers' => [
                    'Authorization' => "Bearer {$token}"
                ],
                'json' => $params,
            ]);

            return $this->processResponse($response);

        } catch (\Throwable $e) {
            // TODO
        }

        return false;
    }

    public function get($uri, $token)
    {
        try {

            $url = $this->instanceUrl . $uri;

            $response = $this->client->request("get", $url, [
                'headers' => [
                    'Authorization' => "Bearer {$token}"
                ]
            ]);

            return $this->processResponse($response);

        } catch (\Throwable $e) {
            // TODO
        }

        return [];
    }

    /**
     * @param $response ResponseInterface
     * @return mixed|string
     * @throws \Exception
     */
    protected function processResponse($response)
    {
        $response = Json::decode($response->getBody()->getContents());

        if (empty($response)) {
            throw new \Exception("请求失败");
        }

        return $response;

    }
}

请求测试类

        $salesForceService = new SalesForceService();

        $this->line("token test");

        $token = $salesForceService->getToken();

        var_dump($token);

        $this->line("post test");

        $params = [
            'data' => [
                'name' => 'PHP远程写入-测试',
                'price' => 88.88
            ]
        ];

        $id = $salesForceService->post("book", $token, $params);

        var_dump($id);

        $this->line("patch test");

        $params = [
            "data" => [
                "id" => $id,
                'name' => 'PHP远程写入-测试-修改',
                'price' => 888.88
            ]
        ];

        $res = $salesForceService->patch("book", $token, $params);

        var_dump($res);

        $this->line("get test");

        $res = $salesForceService->get("book/{$id}", $token);

        var_dump($res);


        $this->line("delete test");

        $res = $salesForceService->delete("book/{$id}", $token);

        var_dump($res);

        $this->line("test finish");

results matching ""

    No results matching ""